summaryrefslogtreecommitdiff
path: root/libgo
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-09-16 15:47:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-09-16 15:47:21 +0000
commitadb0401dac41c81571722312d4586b2693f95aa6 (patch)
treeea2b52e3c258d6b6d9356977c683c7f72a4a5fd5 /libgo
parent5548ca3540bccbc908a45942896d635ea5f1c23f (diff)
Update Go library to r60.
From-SVN: r178910
Diffstat (limited to 'libgo')
-rw-r--r--libgo/MERGE2
-rw-r--r--libgo/Makefile.am605
-rw-r--r--libgo/Makefile.in893
-rw-r--r--libgo/config.h.in15
-rwxr-xr-xlibgo/configure33
-rw-r--r--libgo/configure.ac15
-rw-r--r--libgo/go/archive/tar/reader.go2
-rw-r--r--libgo/go/archive/tar/reader_test.go1
-rw-r--r--libgo/go/archive/zip/reader.go281
-rw-r--r--libgo/go/archive/zip/reader_test.go44
-rw-r--r--libgo/go/archive/zip/struct.go61
-rw-r--r--libgo/go/archive/zip/writer.go244
-rw-r--r--libgo/go/archive/zip/writer_test.go73
-rw-r--r--libgo/go/archive/zip/zip_test.go57
-rw-r--r--libgo/go/asn1/asn1.go117
-rw-r--r--libgo/go/asn1/asn1_test.go78
-rw-r--r--libgo/go/asn1/common.go7
-rw-r--r--libgo/go/asn1/marshal.go54
-rw-r--r--libgo/go/asn1/marshal_test.go13
-rw-r--r--libgo/go/big/arith.go25
-rw-r--r--libgo/go/big/arith_decl.go4
-rw-r--r--libgo/go/big/arith_test.go33
-rw-r--r--libgo/go/big/calibrate_test.go4
-rw-r--r--libgo/go/big/hilbert_test.go13
-rw-r--r--libgo/go/big/int.go302
-rw-r--r--libgo/go/big/int_test.go402
-rw-r--r--libgo/go/big/nat.go388
-rw-r--r--libgo/go/big/nat_test.go403
-rw-r--r--libgo/go/big/rat.go107
-rw-r--r--libgo/go/big/rat_test.go74
-rw-r--r--libgo/go/bufio/bufio.go29
-rw-r--r--libgo/go/bufio/bufio_test.go11
-rw-r--r--libgo/go/builtin/builtin.go135
-rw-r--r--libgo/go/bytes/buffer.go4
-rw-r--r--libgo/go/bytes/buffer_test.go17
-rw-r--r--libgo/go/bytes/bytes.go27
-rw-r--r--libgo/go/bytes/bytes_test.go21
-rw-r--r--libgo/go/compress/bzip2/bzip2.go4
-rw-r--r--libgo/go/compress/bzip2/huffman.go2
-rw-r--r--libgo/go/compress/flate/deflate.go478
-rw-r--r--libgo/go/compress/flate/deflate_test.go16
-rw-r--r--libgo/go/compress/flate/huffman_bit_writer.go94
-rw-r--r--libgo/go/compress/flate/huffman_code.go7
-rw-r--r--libgo/go/compress/flate/inflate.go249
-rw-r--r--libgo/go/compress/gzip/gunzip.go4
-rw-r--r--libgo/go/compress/gzip/gzip_test.go2
-rw-r--r--libgo/go/compress/lzw/reader.go226
-rw-r--r--libgo/go/compress/lzw/reader_test.go2
-rw-r--r--libgo/go/compress/lzw/writer_test.go8
-rw-r--r--libgo/go/compress/zlib/reader.go6
-rw-r--r--libgo/go/compress/zlib/writer.go2
-rw-r--r--libgo/go/compress/zlib/writer_test.go95
-rw-r--r--libgo/go/container/heap/heap.go8
-rw-r--r--libgo/go/container/heap/heap_test.go9
-rw-r--r--libgo/go/container/ring/ring.go9
-rw-r--r--libgo/go/container/ring/ring_test.go10
-rw-r--r--libgo/go/container/vector/defs.go8
-rw-r--r--libgo/go/container/vector/intvector.go20
-rw-r--r--libgo/go/container/vector/intvector_test.go13
-rw-r--r--libgo/go/container/vector/nogen_test.go9
-rw-r--r--libgo/go/container/vector/numbers_test.go8
-rw-r--r--libgo/go/container/vector/stringvector.go20
-rw-r--r--libgo/go/container/vector/stringvector_test.go13
-rw-r--r--libgo/go/container/vector/vector.go20
-rw-r--r--libgo/go/container/vector/vector_test.go13
-rw-r--r--libgo/go/crypto/aes/cipher.go4
-rw-r--r--libgo/go/crypto/blowfish/cipher.go4
-rw-r--r--libgo/go/crypto/cast5/cast5.go2
-rw-r--r--libgo/go/crypto/cipher/ocfb.go8
-rw-r--r--libgo/go/crypto/dsa/dsa.go4
-rw-r--r--libgo/go/crypto/elliptic/elliptic.go2
-rw-r--r--libgo/go/crypto/elliptic/elliptic_test.go4
-rw-r--r--libgo/go/crypto/hmac/hmac_test.go2
-rw-r--r--libgo/go/crypto/ocsp/ocsp.go38
-rw-r--r--libgo/go/crypto/openpgp/armor/armor.go2
-rw-r--r--libgo/go/crypto/openpgp/canonical_text_test.go1
-rw-r--r--libgo/go/crypto/openpgp/elgamal/elgamal.go122
-rw-r--r--libgo/go/crypto/openpgp/elgamal/elgamal_test.go49
-rw-r--r--libgo/go/crypto/openpgp/keys.go248
-rw-r--r--libgo/go/crypto/openpgp/packet/encrypted_key.go132
-rw-r--r--libgo/go/crypto/openpgp/packet/encrypted_key_test.go85
-rw-r--r--libgo/go/crypto/openpgp/packet/literal.go37
-rw-r--r--libgo/go/crypto/openpgp/packet/one_pass_signature.go27
-rw-r--r--libgo/go/crypto/openpgp/packet/packet.go110
-rw-r--r--libgo/go/crypto/openpgp/packet/packet_test.go44
-rw-r--r--libgo/go/crypto/openpgp/packet/private_key.go108
-rw-r--r--libgo/go/crypto/openpgp/packet/private_key_test.go64
-rw-r--r--libgo/go/crypto/openpgp/packet/public_key.go154
-rw-r--r--libgo/go/crypto/openpgp/packet/public_key_test.go36
-rw-r--r--libgo/go/crypto/openpgp/packet/signature.go110
-rw-r--r--libgo/go/crypto/openpgp/packet/signature_test.go22
-rw-r--r--libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go66
-rw-r--r--libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go39
-rw-r--r--libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go95
-rw-r--r--libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go46
-rw-r--r--libgo/go/crypto/openpgp/packet/userid.go56
-rw-r--r--libgo/go/crypto/openpgp/packet/userid_test.go45
-rw-r--r--libgo/go/crypto/openpgp/read.go24
-rw-r--r--libgo/go/crypto/openpgp/read_test.go125
-rw-r--r--libgo/go/crypto/openpgp/s2k/s2k.go22
-rw-r--r--libgo/go/crypto/openpgp/s2k/s2k_test.go25
-rw-r--r--libgo/go/crypto/openpgp/write.go236
-rw-r--r--libgo/go/crypto/openpgp/write_test.go187
-rw-r--r--libgo/go/crypto/rand/rand_windows.go2
-rw-r--r--libgo/go/crypto/rand/util.go80
-rw-r--r--libgo/go/crypto/rsa/pkcs1v15.go4
-rw-r--r--libgo/go/crypto/rsa/rsa.go100
-rw-r--r--libgo/go/crypto/subtle/constant_time_test.go4
-rw-r--r--libgo/go/crypto/tls/common.go2
-rw-r--r--libgo/go/crypto/tls/conn.go10
-rw-r--r--libgo/go/crypto/tls/generate_cert.go10
-rw-r--r--libgo/go/crypto/tls/handshake_client.go6
-rw-r--r--libgo/go/crypto/tls/handshake_server.go10
-rw-r--r--libgo/go/crypto/tls/handshake_server_test.go1
-rw-r--r--libgo/go/crypto/tls/key_agreement.go42
-rw-r--r--libgo/go/crypto/tls/tls.go8
-rw-r--r--libgo/go/crypto/twofish/twofish.go4
-rw-r--r--libgo/go/crypto/x509/cert_pool.go3
-rw-r--r--libgo/go/crypto/x509/pkix/pkix.go167
-rw-r--r--libgo/go/crypto/x509/verify.go11
-rw-r--r--libgo/go/crypto/x509/verify_test.go13
-rw-r--r--libgo/go/crypto/x509/x509.go552
-rw-r--r--libgo/go/crypto/x509/x509_test.go188
-rw-r--r--libgo/go/crypto/xtea/block.go2
-rw-r--r--libgo/go/crypto/xtea/cipher.go4
-rw-r--r--libgo/go/crypto/xtea/xtea_test.go10
-rw-r--r--libgo/go/csv/reader.go372
-rw-r--r--libgo/go/csv/reader_test.go265
-rw-r--r--libgo/go/csv/writer.go122
-rw-r--r--libgo/go/csv/writer_test.go44
-rw-r--r--libgo/go/debug/dwarf/type.go17
-rw-r--r--libgo/go/debug/dwarf/type_test.go1
-rw-r--r--libgo/go/debug/elf/elf.go2
-rw-r--r--libgo/go/debug/elf/file.go81
-rw-r--r--libgo/go/debug/elf/file_test.go70
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj (renamed from libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o)bin3088 -> 3088 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj (renamed from libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o)bin2936 -> 2936 bytes
-rw-r--r--libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.obj (renamed from libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o)bin1884 -> 1884 bytes
-rw-r--r--libgo/go/debug/macho/file.go2
-rw-r--r--libgo/go/debug/pe/file.go41
-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.go1322
-rw-r--r--libgo/go/debug/proc/proc_windows.go17
-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.go21
-rw-r--r--libgo/go/ebnf/ebnf_test.go35
-rw-r--r--libgo/go/ebnf/parser.go37
-rw-r--r--libgo/go/encoding/base32/base32_test.go1
-rw-r--r--libgo/go/encoding/base64/base64.go14
-rw-r--r--libgo/go/encoding/base64/base64_test.go9
-rw-r--r--libgo/go/encoding/binary/binary.go102
-rw-r--r--libgo/go/encoding/binary/binary_test.go73
-rw-r--r--libgo/go/encoding/git85/git.go2
-rw-r--r--libgo/go/encoding/hex/hex.go117
-rw-r--r--libgo/go/encoding/hex/hex_test.go43
-rw-r--r--libgo/go/encoding/line/line.go115
-rw-r--r--libgo/go/encoding/line/line_test.go133
-rw-r--r--libgo/go/encoding/pem/pem.go17
-rw-r--r--libgo/go/exec/exec.go471
-rw-r--r--libgo/go/exec/exec_test.go283
-rw-r--r--libgo/go/exec/lp_plan9.go51
-rw-r--r--libgo/go/exec/lp_test.go6
-rw-r--r--libgo/go/exec/lp_unix.go23
-rw-r--r--libgo/go/exec/lp_windows.go59
-rw-r--r--libgo/go/exp/datafmt/datafmt.go27
-rw-r--r--libgo/go/exp/datafmt/datafmt_test.go21
-rw-r--r--libgo/go/exp/datafmt/parser.go58
-rw-r--r--libgo/go/exp/eval/abort.go85
-rw-r--r--libgo/go/exp/eval/bridge.go164
-rw-r--r--libgo/go/exp/eval/compiler.go92
-rw-r--r--libgo/go/exp/eval/eval_test.go263
-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.go1299
-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/gui/gui.go (renamed from libgo/go/exp/draw/event.go)6
-rw-r--r--libgo/go/exp/gui/x11/auth.go (renamed from libgo/go/exp/draw/x11/auth.go)0
-rw-r--r--libgo/go/exp/gui/x11/conn.go (renamed from libgo/go/exp/draw/x11/conn.go)108
-rw-r--r--libgo/go/exp/norm/composition.go344
-rw-r--r--libgo/go/exp/norm/composition_test.go138
-rw-r--r--libgo/go/exp/norm/forminfo.go188
-rw-r--r--libgo/go/exp/norm/maketables.go855
-rw-r--r--libgo/go/exp/norm/maketesttables.go42
-rw-r--r--libgo/go/exp/norm/norm_test.go14
-rw-r--r--libgo/go/exp/norm/normalize.go99
-rw-r--r--libgo/go/exp/norm/tables.go6580
-rw-r--r--libgo/go/exp/norm/trie.go234
-rw-r--r--libgo/go/exp/norm/trie_test.go107
-rw-r--r--libgo/go/exp/norm/triedata_test.go63
-rw-r--r--libgo/go/exp/norm/triegen.go211
-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/exp/regexp/all_test.go429
-rw-r--r--libgo/go/exp/regexp/exec.go295
-rw-r--r--libgo/go/exp/regexp/find_test.go472
-rw-r--r--libgo/go/exp/regexp/regexp.go795
-rw-r--r--libgo/go/exp/regexp/syntax/compile.go269
-rw-r--r--libgo/go/exp/regexp/syntax/parse.go1797
-rw-r--r--libgo/go/exp/regexp/syntax/parse_test.go350
-rw-r--r--libgo/go/exp/regexp/syntax/perl_groups.go130
-rw-r--r--libgo/go/exp/regexp/syntax/prog.go237
-rw-r--r--libgo/go/exp/regexp/syntax/prog_test.go91
-rw-r--r--libgo/go/exp/regexp/syntax/regexp.go284
-rw-r--r--libgo/go/exp/regexp/syntax/simplify.go151
-rw-r--r--libgo/go/exp/regexp/syntax/simplify_test.go151
-rw-r--r--libgo/go/exp/template/html/context.go98
-rw-r--r--libgo/go/exp/template/html/escape.go105
-rw-r--r--libgo/go/exp/template/html/escape_test.go75
-rw-r--r--libgo/go/exp/wingui/winapi.go23
-rw-r--r--libgo/go/exp/wingui/zwinapi.go70
-rw-r--r--libgo/go/expvar/expvar.go1
-rw-r--r--libgo/go/expvar/expvar_test.go30
-rw-r--r--libgo/go/flag/export_test.go22
-rw-r--r--libgo/go/flag/flag.go416
-rw-r--r--libgo/go/flag/flag_test.go102
-rw-r--r--libgo/go/fmt/doc.go17
-rw-r--r--libgo/go/fmt/fmt_test.go95
-rw-r--r--libgo/go/fmt/format.go44
-rw-r--r--libgo/go/fmt/print.go103
-rw-r--r--libgo/go/fmt/scan.go70
-rw-r--r--libgo/go/fmt/scan_test.go68
-rw-r--r--libgo/go/go/ast/ast.go66
-rw-r--r--libgo/go/go/ast/filter.go130
-rw-r--r--libgo/go/go/ast/print.go9
-rw-r--r--libgo/go/go/ast/print_test.go5
-rw-r--r--libgo/go/go/ast/resolve.go90
-rw-r--r--libgo/go/go/ast/scope.go22
-rw-r--r--libgo/go/go/ast/walk.go7
-rw-r--r--libgo/go/go/build/build.go444
-rw-r--r--libgo/go/go/build/build_test.go61
-rw-r--r--libgo/go/go/build/cgotest/cgotest.go19
-rw-r--r--libgo/go/go/build/cmdtest/main.go12
-rw-r--r--libgo/go/go/build/dir.go172
-rw-r--r--libgo/go/go/build/path.go182
-rw-r--r--libgo/go/go/build/pkgtest/pkgtest.go9
-rw-r--r--libgo/go/go/build/syslist_test.go62
-rw-r--r--libgo/go/go/doc/comment.go16
-rw-r--r--libgo/go/go/doc/doc.go55
-rw-r--r--libgo/go/go/parser/interface.go37
-rw-r--r--libgo/go/go/parser/parser.go283
-rw-r--r--libgo/go/go/parser/parser_test.go28
-rw-r--r--libgo/go/go/printer/nodes.go240
-rw-r--r--libgo/go/go/printer/performance_test.go4
-rw-r--r--libgo/go/go/printer/printer.go57
-rw-r--r--libgo/go/go/printer/printer_test.go10
-rw-r--r--libgo/go/go/printer/testdata/comments.golden20
-rw-r--r--libgo/go/go/printer/testdata/comments.input2
-rw-r--r--libgo/go/go/printer/testdata/comments.x11
-rw-r--r--libgo/go/go/printer/testdata/declarations.golden61
-rw-r--r--libgo/go/go/printer/testdata/declarations.input29
-rw-r--r--libgo/go/go/printer/testdata/expressions.golden25
-rw-r--r--libgo/go/go/printer/testdata/expressions.raw25
-rw-r--r--libgo/go/go/printer/testdata/parser.go99
-rw-r--r--libgo/go/go/printer/testdata/statements.golden31
-rw-r--r--libgo/go/go/printer/testdata/statements.input13
-rw-r--r--libgo/go/go/scanner/errors.go34
-rw-r--r--libgo/go/go/scanner/scanner.go59
-rw-r--r--libgo/go/go/scanner/scanner_test.go44
-rw-r--r--libgo/go/go/token/position.go35
-rw-r--r--libgo/go/go/token/position_test.go9
-rw-r--r--libgo/go/go/token/token.go8
-rw-r--r--libgo/go/go/typechecker/scope.go6
-rw-r--r--libgo/go/go/typechecker/type.go7
-rw-r--r--libgo/go/go/typechecker/typechecker.go20
-rw-r--r--libgo/go/go/typechecker/typechecker_test.go5
-rw-r--r--libgo/go/go/typechecker/universe.go2
-rw-r--r--libgo/go/go/types/check.go226
-rw-r--r--libgo/go/go/types/check_test.go215
-rw-r--r--libgo/go/go/types/const.go15
-rw-r--r--libgo/go/go/types/exportdata.go11
-rw-r--r--libgo/go/go/types/gcimporter.go273
-rw-r--r--libgo/go/go/types/gcimporter_test.go28
-rw-r--r--libgo/go/go/types/testdata/exports.go23
-rw-r--r--libgo/go/go/types/types.go177
-rw-r--r--libgo/go/go/types/universe.go23
-rw-r--r--libgo/go/gob/codec_test.go53
-rw-r--r--libgo/go/gob/decode.go46
-rw-r--r--libgo/go/gob/decoder.go12
-rw-r--r--libgo/go/gob/doc.go39
-rw-r--r--libgo/go/gob/encode.go47
-rw-r--r--libgo/go/gob/encoder.go2
-rw-r--r--libgo/go/gob/encoder_test.go29
-rw-r--r--libgo/go/gob/gobencdec_test.go32
-rw-r--r--libgo/go/gob/timing_test.go4
-rw-r--r--libgo/go/gob/type.go33
-rw-r--r--libgo/go/hash/crc32/crc32.go37
-rw-r--r--libgo/go/hash/crc32/crc32_amd64.go25
-rw-r--r--libgo/go/hash/crc32/crc32_generic.go12
-rw-r--r--libgo/go/hash/crc32/crc32_test.go103
-rw-r--r--libgo/go/hash/fnv/fnv.go17
-rw-r--r--libgo/go/html/const.go90
-rw-r--r--libgo/go/html/doc.go1
-rw-r--r--libgo/go/html/entity.go3
-rw-r--r--libgo/go/html/entity_test.go3
-rw-r--r--libgo/go/html/escape.go28
-rw-r--r--libgo/go/html/node.go147
-rw-r--r--libgo/go/html/parse.go312
-rw-r--r--libgo/go/html/parse_test.go6
-rw-r--r--libgo/go/html/testdata/webkit/comments01.dat17
-rw-r--r--libgo/go/html/testdata/webkit/doctype01.dat63
-rw-r--r--libgo/go/html/testdata/webkit/dom2string.js135
-rw-r--r--libgo/go/html/testdata/webkit/entities01.dat9
-rw-r--r--libgo/go/html/testdata/webkit/entities02.dat120
-rw-r--r--libgo/go/html/testdata/webkit/tests1.dat59
-rw-r--r--libgo/go/html/testdata/webkit/tests10.dat369
-rw-r--r--libgo/go/html/testdata/webkit/tests13.dat9
-rw-r--r--libgo/go/html/testdata/webkit/tests14.dat2
-rw-r--r--libgo/go/html/testdata/webkit/tests15.dat2
-rw-r--r--libgo/go/html/testdata/webkit/tests2.dat27
-rw-r--r--libgo/go/html/testdata/webkit/tests3.dat12
-rw-r--r--libgo/go/html/testdata/webkit/tests6.dat10
-rw-r--r--libgo/go/html/testdata/webkit/tests9.dat27
-rw-r--r--libgo/go/html/testdata/webkit/webkit01.dat460
-rw-r--r--libgo/go/html/token.go336
-rw-r--r--libgo/go/html/token_test.go87
-rw-r--r--libgo/go/http/cgi/child.go16
-rw-r--r--libgo/go/http/cgi/child_test.go8
-rw-r--r--libgo/go/http/cgi/host.go88
-rw-r--r--libgo/go/http/cgi/host_test.go173
-rw-r--r--libgo/go/http/chunked.go25
-rw-r--r--libgo/go/http/client.go172
-rw-r--r--libgo/go/http/client_test.go178
-rw-r--r--libgo/go/http/cookie.go161
-rw-r--r--libgo/go/http/cookie_test.go163
-rw-r--r--libgo/go/http/fs.go99
-rw-r--r--libgo/go/http/fs_test.go178
-rw-r--r--libgo/go/http/header.go5
-rw-r--r--libgo/go/http/header_test.go10
-rw-r--r--libgo/go/http/httptest/server.go55
-rw-r--r--libgo/go/http/persist.go19
-rw-r--r--libgo/go/http/proxy_test.go4
-rw-r--r--libgo/go/http/readrequest_test.go85
-rw-r--r--libgo/go/http/request.go263
-rw-r--r--libgo/go/http/request_test.go40
-rw-r--r--libgo/go/http/requestwrite_test.go156
-rw-r--r--libgo/go/http/response.go45
-rw-r--r--libgo/go/http/response_test.go62
-rw-r--r--libgo/go/http/responsewrite_test.go14
-rw-r--r--libgo/go/http/reverseproxy.go63
-rw-r--r--libgo/go/http/reverseproxy_test.go20
-rw-r--r--libgo/go/http/serve_test.go332
-rw-r--r--libgo/go/http/server.go273
-rw-r--r--libgo/go/http/sniff.go214
-rw-r--r--libgo/go/http/sniff_test.go80
-rw-r--r--libgo/go/http/spdy/protocol.go367
-rw-r--r--libgo/go/http/spdy/protocol_test.go259
-rw-r--r--libgo/go/http/spdy/read.go313
-rw-r--r--libgo/go/http/spdy/spdy_test.go497
-rw-r--r--libgo/go/http/spdy/types.go370
-rw-r--r--libgo/go/http/spdy/write.go286
-rw-r--r--libgo/go/http/testdata/index.html1
-rw-r--r--libgo/go/http/testdata/style.css1
-rw-r--r--libgo/go/http/transfer.go64
-rw-r--r--libgo/go/http/transport.go247
-rw-r--r--libgo/go/http/transport_test.go149
-rw-r--r--libgo/go/image/bmp/reader.go151
-rw-r--r--libgo/go/image/color.go24
-rw-r--r--libgo/go/image/decode_test.go68
-rw-r--r--libgo/go/image/draw/bench_test.go206
-rw-r--r--libgo/go/image/draw/clip_test.go193
-rw-r--r--libgo/go/image/draw/draw.go (renamed from libgo/go/exp/draw/draw.go)453
-rw-r--r--libgo/go/image/draw/draw_test.go (renamed from libgo/go/exp/draw/draw_test.go)180
-rw-r--r--libgo/go/image/geom.go19
-rw-r--r--libgo/go/image/gif/reader.go112
-rw-r--r--libgo/go/image/image.go554
-rw-r--r--libgo/go/image/image_test.go113
-rw-r--r--libgo/go/image/jpeg/idct.go124
-rw-r--r--libgo/go/image/jpeg/reader.go237
-rw-r--r--libgo/go/image/jpeg/writer.go36
-rw-r--r--libgo/go/image/png/writer.go90
-rw-r--r--libgo/go/image/png/writer_test.go73
-rw-r--r--libgo/go/image/testdata/video-001.5bpp.gifbin0 -> 6214 bytes
-rw-r--r--libgo/go/image/testdata/video-001.interlaced.gifbin0 -> 14142 bytes
-rw-r--r--libgo/go/image/testdata/video-005.gray.jpegbin0 -> 5618 bytes
-rw-r--r--libgo/go/image/testdata/video-005.gray.pngbin0 -> 14974 bytes
-rw-r--r--libgo/go/image/tiff/consts.go1
-rw-r--r--libgo/go/image/tiff/reader.go132
-rw-r--r--libgo/go/image/tiff/reader_test.go25
-rw-r--r--libgo/go/image/tiff/testdata/no_rps.tiffbin0 -> 1294 bytes
-rw-r--r--libgo/go/image/ycbcr/ycbcr.go11
-rw-r--r--libgo/go/index/suffixarray/qsufsort.go4
-rw-r--r--libgo/go/index/suffixarray/suffixarray.go11
-rw-r--r--libgo/go/index/suffixarray/suffixarray_test.go18
-rw-r--r--libgo/go/io/io.go117
-rw-r--r--libgo/go/io/ioutil/ioutil.go19
-rw-r--r--libgo/go/io/ioutil/ioutil_test.go1
-rw-r--r--libgo/go/io/multi_test.go5
-rw-r--r--libgo/go/json/decode.go15
-rw-r--r--libgo/go/json/decode_test.go34
-rw-r--r--libgo/go/json/encode.go91
-rw-r--r--libgo/go/json/encode_test.go44
-rw-r--r--libgo/go/json/scanner_test.go2
-rw-r--r--libgo/go/json/tagkey_test.go95
-rw-r--r--libgo/go/log/log.go20
-rw-r--r--libgo/go/mail/message.go524
-rw-r--r--libgo/go/mail/message_test.go278
-rw-r--r--libgo/go/math/acosh.go1
-rw-r--r--libgo/go/math/asin.go1
-rw-r--r--libgo/go/math/asinh.go1
-rw-r--r--libgo/go/math/atanh.go1
-rw-r--r--libgo/go/math/erf.go1
-rw-r--r--libgo/go/math/exp_port.go1
-rw-r--r--libgo/go/math/expm1.go1
-rw-r--r--libgo/go/math/floor.go1
-rw-r--r--libgo/go/math/fmod.go1
-rw-r--r--libgo/go/math/log.go2
-rw-r--r--libgo/go/math/log1p.go1
-rw-r--r--libgo/go/math/sin.go1
-rw-r--r--libgo/go/math/sinh.go1
-rw-r--r--libgo/go/math/sqrt_port.go6
-rw-r--r--libgo/go/math/tan.go1
-rw-r--r--libgo/go/math/tanh.go1
-rw-r--r--libgo/go/mime/grammar.go4
-rw-r--r--libgo/go/mime/mediatype.go15
-rw-r--r--libgo/go/mime/mediatype_test.go3
-rw-r--r--libgo/go/mime/multipart/formdata.go2
-rw-r--r--libgo/go/mime/multipart/formdata_test.go4
-rw-r--r--libgo/go/mime/multipart/multipart.go90
-rw-r--r--libgo/go/mime/multipart/multipart_test.go97
-rw-r--r--libgo/go/mime/multipart/writer.go157
-rw-r--r--libgo/go/mime/multipart/writer_test.go78
-rw-r--r--libgo/go/mime/type.go2
-rw-r--r--libgo/go/net/dial.go93
-rw-r--r--libgo/go/net/dialgoogle_test.go8
-rw-r--r--libgo/go/net/dict/dict.go7
-rw-r--r--libgo/go/net/dnsclient.go398
-rw-r--r--libgo/go/net/dnsclient_unix.go261
-rw-r--r--libgo/go/net/dnsconfig.go1
-rw-r--r--libgo/go/net/dnsmsg.go56
-rw-r--r--libgo/go/net/dnsmsg_test.go7
-rw-r--r--libgo/go/net/dnsname_test.go4
-rw-r--r--libgo/go/net/fd.go14
-rw-r--r--libgo/go/net/fd_linux.go11
-rw-r--r--libgo/go/net/fd_openbsd.go116
-rw-r--r--libgo/go/net/fd_windows.go65
-rw-r--r--libgo/go/net/file_plan9.go33
-rw-r--r--libgo/go/net/file_test.go10
-rw-r--r--libgo/go/net/hosts_test.go2
-rw-r--r--libgo/go/net/interface.go132
-rw-r--r--libgo/go/net/interface_bsd.go171
-rw-r--r--libgo/go/net/interface_darwin.go80
-rw-r--r--libgo/go/net/interface_freebsd.go80
-rw-r--r--libgo/go/net/interface_linux.go262
-rw-r--r--libgo/go/net/interface_openbsd.go16
-rw-r--r--libgo/go/net/interface_stub.go30
-rw-r--r--libgo/go/net/interface_test.go73
-rw-r--r--libgo/go/net/interface_windows.go158
-rw-r--r--libgo/go/net/ip.go65
-rw-r--r--libgo/go/net/ip_test.go112
-rw-r--r--libgo/go/net/ipraw_test.go9
-rw-r--r--libgo/go/net/iprawsock.go317
-rw-r--r--libgo/go/net/iprawsock_plan9.go99
-rw-r--r--libgo/go/net/iprawsock_posix.go305
-rw-r--r--libgo/go/net/ipsock.go202
-rw-r--r--libgo/go/net/ipsock_plan9.go305
-rw-r--r--libgo/go/net/ipsock_posix.go174
-rw-r--r--libgo/go/net/lookup.go50
-rw-r--r--libgo/go/net/lookup_plan9.go226
-rw-r--r--libgo/go/net/lookup_test.go (renamed from libgo/go/net/srv_test.go)28
-rw-r--r--libgo/go/net/lookup_unix.go111
-rw-r--r--libgo/go/net/lookup_windows.go (renamed from libgo/go/net/resolv_windows.go)111
-rw-r--r--libgo/go/net/net.go2
-rw-r--r--libgo/go/net/net_test.go4
-rw-r--r--libgo/go/net/newpollserver.go14
-rw-r--r--libgo/go/net/parse_test.go4
-rw-r--r--libgo/go/net/sendfile_linux.go84
-rw-r--r--libgo/go/net/sendfile_stub.go14
-rw-r--r--libgo/go/net/sendfile_windows.go68
-rw-r--r--libgo/go/net/server_test.go48
-rw-r--r--libgo/go/net/sock.go42
-rw-r--r--libgo/go/net/sock_windows.go2
-rw-r--r--libgo/go/net/tcpsock.go262
-rw-r--r--libgo/go/net/tcpsock_plan9.go63
-rw-r--r--libgo/go/net/tcpsock_posix.go283
-rw-r--r--libgo/go/net/textproto/reader.go64
-rw-r--r--libgo/go/net/udpsock.go290
-rw-r--r--libgo/go/net/udpsock_plan9.go187
-rw-r--r--libgo/go/net/udpsock_posix.go294
-rw-r--r--libgo/go/net/unixsock.go399
-rw-r--r--libgo/go/net/unixsock_plan9.go105
-rw-r--r--libgo/go/net/unixsock_posix.go418
-rw-r--r--libgo/go/netchan/common.go4
-rw-r--r--libgo/go/netchan/export.go12
-rw-r--r--libgo/go/netchan/import.go51
-rw-r--r--libgo/go/netchan/netchan_test.go10
-rw-r--r--libgo/go/old/template/doc.go91
-rw-r--r--libgo/go/old/template/execute.go346
-rw-r--r--libgo/go/old/template/format.go (renamed from libgo/go/template/format.go)0
-rw-r--r--libgo/go/old/template/parse.go (renamed from libgo/go/template/template.go)649
-rw-r--r--libgo/go/old/template/template_test.go (renamed from libgo/go/template/template_test.go)45
-rw-r--r--libgo/go/os/dir.go31
-rw-r--r--libgo/go/os/dir_plan9.go82
-rw-r--r--libgo/go/os/dir_unix.go45
-rw-r--r--libgo/go/os/env_plan9.go15
-rw-r--r--libgo/go/os/env_unix.go1
-rw-r--r--libgo/go/os/env_windows.go2
-rw-r--r--libgo/go/os/error.go13
-rw-r--r--libgo/go/os/error_plan9.go1
-rw-r--r--libgo/go/os/error_posix.go2
-rw-r--r--libgo/go/os/exec.go14
-rw-r--r--libgo/go/os/exec_plan9.go45
-rw-r--r--libgo/go/os/exec_posix.go44
-rw-r--r--libgo/go/os/exec_unix.go14
-rw-r--r--libgo/go/os/exec_windows.go22
-rw-r--r--libgo/go/os/file.go30
-rw-r--r--libgo/go/os/file_plan9.go108
-rw-r--r--libgo/go/os/file_posix.go22
-rw-r--r--libgo/go/os/file_unix.go69
-rw-r--r--libgo/go/os/inotify/inotify_linux.go7
-rw-r--r--libgo/go/os/inotify/inotify_linux_test.go1
-rw-r--r--libgo/go/os/mkunixsignals.sh (renamed from libgo/go/os/signal/mkunix.sh)4
-rw-r--r--libgo/go/os/os_test.go147
-rw-r--r--libgo/go/os/path.go10
-rw-r--r--libgo/go/os/path_plan9.go15
-rw-r--r--libgo/go/os/path_test.go26
-rw-r--r--libgo/go/os/path_unix.go15
-rw-r--r--libgo/go/os/path_windows.go16
-rw-r--r--libgo/go/os/proc.go1
-rw-r--r--libgo/go/os/signal/signal.go25
-rw-r--r--libgo/go/os/signal/signal_test.go5
-rw-r--r--libgo/go/os/stat_openbsd.go32
-rw-r--r--libgo/go/os/stat_plan9.go18
-rw-r--r--libgo/go/os/str.go20
-rw-r--r--libgo/go/os/sys_linux.go1
-rw-r--r--libgo/go/os/sys_plan9.go1
-rw-r--r--libgo/go/os/time.go1
-rw-r--r--libgo/go/os/types.go2
-rw-r--r--libgo/go/os/user/lookup_unix.go4
-rw-r--r--libgo/go/os/user/user.go2
-rw-r--r--libgo/go/os/user/user_test.go8
-rw-r--r--libgo/go/patch/patch.go2
-rw-r--r--libgo/go/patch/textdiff.go10
-rw-r--r--libgo/go/path/filepath/match.go9
-rw-r--r--libgo/go/path/filepath/match_test.go9
-rw-r--r--libgo/go/path/filepath/path.go59
-rw-r--r--libgo/go/path/filepath/path_plan9.go19
-rw-r--r--libgo/go/path/filepath/path_test.go115
-rw-r--r--libgo/go/path/filepath/path_unix.go19
-rw-r--r--libgo/go/path/filepath/path_windows.go45
-rw-r--r--libgo/go/rand/rand_test.go8
-rw-r--r--libgo/go/reflect/all_test.go86
-rw-r--r--libgo/go/reflect/type.go148
-rw-r--r--libgo/go/reflect/value.go68
-rw-r--r--libgo/go/regexp/all_test.go2
-rw-r--r--libgo/go/regexp/regexp.go21
-rw-r--r--libgo/go/rpc/client.go11
-rw-r--r--libgo/go/rpc/debug.go20
-rw-r--r--libgo/go/rpc/jsonrpc/all_test.go8
-rw-r--r--libgo/go/rpc/jsonrpc/client.go12
-rw-r--r--libgo/go/rpc/jsonrpc/server.go12
-rw-r--r--libgo/go/rpc/server.go131
-rw-r--r--libgo/go/rpc/server_test.go91
-rw-r--r--libgo/go/runtime/append_test.go52
-rw-r--r--libgo/go/runtime/chan_test.go322
-rw-r--r--libgo/go/runtime/closure_test.go53
-rw-r--r--libgo/go/runtime/debug/stack.go2
-rw-r--r--libgo/go/runtime/debug/stack_test.go6
-rw-r--r--libgo/go/runtime/error.go5
-rw-r--r--libgo/go/runtime/export_test.go10
-rw-r--r--libgo/go/runtime/mem.go9
-rw-r--r--libgo/go/runtime/pprof/pprof_test.go2
-rw-r--r--libgo/go/runtime/proc_test.go92
-rw-r--r--libgo/go/runtime/sema_test.go100
-rw-r--r--libgo/go/runtime/softfloat64.go4
-rw-r--r--libgo/go/runtime/symtab_test.go55
-rw-r--r--libgo/go/scanner/scanner.go35
-rw-r--r--libgo/go/scanner/scanner_test.go70
-rw-r--r--libgo/go/smtp/smtp.go9
-rw-r--r--libgo/go/smtp/smtp_test.go4
-rw-r--r--libgo/go/sort/search.go22
-rw-r--r--libgo/go/sort/search_test.go21
-rw-r--r--libgo/go/sort/sort.go74
-rw-r--r--libgo/go/sort/sort_test.go56
-rw-r--r--libgo/go/strconv/atob.go4
-rw-r--r--libgo/go/strconv/atob_test.go2
-rw-r--r--libgo/go/strconv/atof.go10
-rw-r--r--libgo/go/strconv/atof_test.go3
-rw-r--r--libgo/go/strconv/atoi.go8
-rw-r--r--libgo/go/strconv/decimal.go2
-rw-r--r--libgo/go/strconv/fp_test.go6
-rw-r--r--libgo/go/strconv/quote.go128
-rw-r--r--libgo/go/strconv/quote_test.go81
-rw-r--r--libgo/go/strings/reader.go74
-rw-r--r--libgo/go/strings/strings.go27
-rw-r--r--libgo/go/strings/strings_test.go89
-rw-r--r--libgo/go/sync/atomic/atomic.c28
-rw-r--r--libgo/go/sync/atomic/atomic_test.go102
-rw-r--r--libgo/go/sync/atomic/doc.go6
-rw-r--r--libgo/go/sync/cond.go69
-rw-r--r--libgo/go/sync/cond_test.go27
-rw-r--r--libgo/go/sync/mutex.go63
-rw-r--r--libgo/go/sync/mutex_test.go102
-rw-r--r--libgo/go/sync/once.go14
-rw-r--r--libgo/go/sync/once_test.go25
-rw-r--r--libgo/go/sync/rwmutex.go67
-rw-r--r--libgo/go/sync/rwmutex_test.go83
-rw-r--r--libgo/go/sync/waitgroup.go41
-rw-r--r--libgo/go/sync/waitgroup_test.go105
-rw-r--r--libgo/go/syslog/syslog_unix.go2
-rw-r--r--libgo/go/tabwriter/tabwriter.go27
-rw-r--r--libgo/go/tabwriter/tabwriter_test.go10
-rw-r--r--libgo/go/template/doc.go313
-rw-r--r--libgo/go/template/exec.go674
-rw-r--r--libgo/go/template/exec_test.go613
-rw-r--r--libgo/go/template/funcs.go368
-rw-r--r--libgo/go/template/helper.go238
-rw-r--r--libgo/go/template/parse.go85
-rw-r--r--libgo/go/template/parse/lex.go472
-rw-r--r--libgo/go/template/parse/lex_test.go223
-rw-r--r--libgo/go/template/parse/node.go470
-rw-r--r--libgo/go/template/parse/parse.go436
-rw-r--r--libgo/go/template/parse/parse_test.go259
-rw-r--r--libgo/go/template/parse/set.go50
-rw-r--r--libgo/go/template/set.go108
-rw-r--r--libgo/go/template/set_test.go239
-rw-r--r--libgo/go/template/testdata/file1.tmpl2
-rw-r--r--libgo/go/template/testdata/file2.tmpl2
-rw-r--r--libgo/go/template/testdata/tmpl1.tmpl1
-rw-r--r--libgo/go/template/testdata/tmpl2.tmpl1
-rw-r--r--libgo/go/testing/benchmark.go67
-rw-r--r--libgo/go/testing/iotest/reader.go22
-rw-r--r--libgo/go/testing/testing.go67
-rw-r--r--libgo/go/time/format.go140
-rw-r--r--libgo/go/time/sleep.go2
-rw-r--r--libgo/go/time/sleep_test.go2
-rw-r--r--libgo/go/time/sys.go13
-rw-r--r--libgo/go/time/sys_plan9.go18
-rw-r--r--libgo/go/time/sys_posix.go18
-rw-r--r--libgo/go/time/tick.go4
-rw-r--r--libgo/go/time/time.go30
-rw-r--r--libgo/go/time/time_test.go255
-rw-r--r--libgo/go/time/zoneinfo_plan9.go59
-rw-r--r--libgo/go/time/zoneinfo_posix.go62
-rw-r--r--libgo/go/time/zoneinfo_unix.go58
-rw-r--r--libgo/go/time/zoneinfo_windows.go12
-rw-r--r--libgo/go/unicode/casetables.go1
-rw-r--r--libgo/go/unicode/digit.go2
-rw-r--r--libgo/go/unicode/digit_test.go2
-rw-r--r--libgo/go/unicode/graphic.go132
-rw-r--r--libgo/go/unicode/graphic_test.go122
-rw-r--r--libgo/go/unicode/letter.go186
-rw-r--r--libgo/go/unicode/letter_test.go52
-rw-r--r--libgo/go/unicode/script_test.go17
-rw-r--r--libgo/go/unicode/tables.go9275
-rw-r--r--libgo/go/url/url.go (renamed from libgo/go/http/url.go)224
-rw-r--r--libgo/go/url/url_test.go (renamed from libgo/go/http/url_test.go)127
-rw-r--r--libgo/go/utf8/utf8.go120
-rw-r--r--libgo/go/websocket/client.go44
-rw-r--r--libgo/go/websocket/server.go3
-rw-r--r--libgo/go/websocket/websocket.go2
-rw-r--r--libgo/go/websocket/websocket_test.go9
-rw-r--r--libgo/go/xml/atom_test.go50
-rw-r--r--libgo/go/xml/embed_test.go10
-rw-r--r--libgo/go/xml/marshal.go228
-rw-r--r--libgo/go/xml/marshal_test.go305
-rw-r--r--libgo/go/xml/read.go128
-rw-r--r--libgo/go/xml/read_test.go78
-rw-r--r--libgo/go/xml/xml.go636
-rw-r--r--libgo/go/xml/xml_test.go29
-rw-r--r--libgo/merge.sh6
-rwxr-xr-xlibgo/mksysinfo.sh108
-rw-r--r--libgo/runtime/go-go.c29
-rw-r--r--libgo/runtime/go-gomaxprocs.c14
-rw-r--r--libgo/runtime/go-rand.c18
-rw-r--r--libgo/runtime/go-reflect-chan.c18
-rw-r--r--libgo/runtime/go-reflect-map.c37
-rw-r--r--libgo/runtime/go-select.c4
-rw-r--r--libgo/runtime/go-semacquire.c4
-rw-r--r--libgo/runtime/goc2c.c106
-rw-r--r--libgo/runtime/malloc.goc71
-rw-r--r--libgo/runtime/malloc.h20
-rw-r--r--libgo/runtime/mcache.c4
-rw-r--r--libgo/runtime/mgc0.c42
-rw-r--r--libgo/runtime/mheap.c10
-rw-r--r--libgo/runtime/mprof.goc2
-rw-r--r--libgo/runtime/runtime.h8
-rw-r--r--libgo/syscalls/exec.go101
-rw-r--r--libgo/syscalls/netlink_linux.go227
-rw-r--r--libgo/syscalls/socket.go4
-rw-r--r--libgo/syscalls/socket_bsd.go4
-rw-r--r--libgo/syscalls/socket_irix.go6
-rw-r--r--libgo/syscalls/socket_linux.go90
-rw-r--r--libgo/syscalls/socket_solaris.go4
-rw-r--r--libgo/syscalls/syscall_linux.go18
-rw-r--r--libgo/testsuite/Makefile.in1
-rwxr-xr-xlibgo/testsuite/gotest22
713 files changed, 58730 insertions, 30293 deletions
diff --git a/libgo/MERGE b/libgo/MERGE
index 9cee703c403..f0849cc1a18 100644
--- a/libgo/MERGE
+++ b/libgo/MERGE
@@ -1,4 +1,4 @@
-aea0ba6e5935
+504f4e9b079c
The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources.
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 740e8d257f4..2881c6d7c09 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -106,6 +106,7 @@ toolexeclibgo_DATA = \
bytes.gox \
cmath.gox \
crypto.gox \
+ csv.gox \
ebnf.gox \
exec.gox \
expvar.gox \
@@ -120,6 +121,7 @@ toolexeclibgo_DATA = \
json.gox \
log.gox \
math.gox \
+ mail.gox \
mime.gox \
net.gox \
netchan.gox \
@@ -145,6 +147,7 @@ toolexeclibgo_DATA = \
time.gox \
try.gox \
unicode.gox \
+ url.gox \
utf16.gox \
utf8.gox \
websocket.gox \
@@ -206,10 +209,16 @@ toolexeclibgocryptoopenpgpdir = $(toolexeclibgocryptodir)/openpgp
toolexeclibgocryptoopenpgp_DATA = \
crypto/openpgp/armor.gox \
+ crypto/openpgp/elgamal.gox \
crypto/openpgp/error.gox \
crypto/openpgp/packet.gox \
crypto/openpgp/s2k.gox
+toolexeclibgocryptox509dir = $(toolexeclibgocryptodir)/x509
+
+toolexeclibgocryptox509_DATA = \
+ crypto/x509/pkix.gox
+
toolexeclibgodebugdir = $(toolexeclibgodir)/debug
toolexeclibgodebug_DATA = \
@@ -217,8 +226,7 @@ toolexeclibgodebug_DATA = \
debug/elf.gox \
debug/gosym.gox \
debug/macho.gox \
- debug/pe.gox \
- debug/proc.gox
+ debug/pe.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
@@ -227,7 +235,6 @@ toolexeclibgoencoding_DATA = \
encoding/base32.gox \
encoding/base64.gox \
encoding/binary.gox \
- encoding/line.gox \
encoding/git85.gox \
encoding/hex.gox \
encoding/pem.gox
@@ -236,13 +243,30 @@ toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
exp/datafmt.gox \
- exp/draw.gox \
- exp/eval.gox
+ exp/gui.gox \
+ exp/norm.gox \
+ exp/regexp.gox
+
+toolexeclibgoexpguidir = $(toolexeclibgoexpdir)/gui
+
+toolexeclibgoexpgui_DATA = \
+ exp/gui/x11.gox
+
+toolexeclibgoexpregexpdir = $(toolexeclibgoexpdir)/regexp
+
+toolexeclibgoexpregexp_DATA = \
+ exp/regexp/syntax.gox
+
+toolexeclibgoexptemplatedir = $(toolexeclibgoexpdir)/template
+
+toolexeclibgoexptemplate_DATA = \
+ exp/template/html.gox
toolexeclibgogodir = $(toolexeclibgodir)/go
toolexeclibgogo_DATA = \
go/ast.gox \
+ go/build.gox \
go/doc.gox \
go/parser.gox \
go/printer.gox \
@@ -271,6 +295,8 @@ toolexeclibgohttp_DATA = \
toolexeclibgoimagedir = $(toolexeclibgodir)/image
toolexeclibgoimage_DATA = \
+ image/bmp.gox \
+ image/draw.gox \
image/gif.gox \
image/jpeg.gox \
image/png.gox \
@@ -298,6 +324,11 @@ toolexeclibgonet_DATA = \
net/dict.gox \
net/textproto.gox
+toolexeclibgoolddir = $(toolexeclibgodir)/old
+
+toolexeclibgoold_DATA = \
+ old/template.gox
+
toolexeclibgoosdir = $(toolexeclibgodir)/os
if LIBGO_IS_LINUX
@@ -328,6 +359,11 @@ toolexeclibgoruntime_DATA = \
runtime/debug.gox \
runtime/pprof.gox
+toolexeclibgotemplatedir = $(toolexeclibgodir)/template
+
+toolexeclibgotemplate_DATA = \
+ template/parse.gox
+
toolexeclibgosyncdir = $(toolexeclibgodir)/sync
toolexeclibgosync_DATA = \
@@ -394,6 +430,7 @@ runtime_files = \
runtime/go-panic.c \
runtime/go-panic-defer.c \
runtime/go-print.c \
+ runtime/go-rand.c \
runtime/go-rec-big.c \
runtime/go-rec-nb-big.c \
runtime/go-rec-nb-small.c \
@@ -519,6 +556,10 @@ go_cmath_files = \
go_crypto_files = \
go/crypto/crypto.go
+go_csv_files = \
+ go/csv/reader.go \
+ go/csv/writer.go
+
go_ebnf_files = \
go/ebnf/ebnf.go \
go/ebnf/parser.go
@@ -552,9 +593,11 @@ go_hash_files = \
go/hash/hash.go
go_html_files = \
+ go/html/const.go \
go/html/doc.go \
go/html/entity.go \
go/html/escape.go \
+ go/html/node.go \
go/html/parse.go \
go/html/token.go
@@ -571,10 +614,10 @@ go_http_files = \
go/http/response.go \
go/http/reverseproxy.go \
go/http/server.go \
+ go/http/sniff.go \
go/http/status.go \
go/http/transfer.go \
- go/http/transport.go \
- go/http/url.go
+ go/http/transport.go
go_image_files = \
go/image/color.go \
@@ -646,6 +689,9 @@ go_math_files = \
go/math/tanh.go \
go/math/unsafe.go
+go_mail_files = \
+ go/mail/message.go
+
go_mime_files = \
go/mime/grammar.go \
go/mime/mediatype.go \
@@ -684,11 +730,24 @@ endif
endif
endif
+if LIBGO_IS_LINUX
+go_net_sendfile_file = go/net/sendfile_linux.go
+else
+go_net_sendfile_file = go/net/sendfile_stub.go
+endif
+
+if LIBGO_IS_LINUX
+go_net_interface_file = go/net/interface_linux.go
+else
+go_net_interface_file = go/net/interface_stub.go
+endif
+
go_net_files = \
go/net/cgo_unix.go \
$(go_net_cgo_file) \
go/net/dial.go \
go/net/dnsclient.go \
+ go/net/dnsclient_unix.go \
go/net/dnsconfig.go \
go/net/dnsmsg.go \
$(go_net_newpollserver_file) \
@@ -696,19 +755,27 @@ go_net_files = \
$(go_net_fd_os_file) \
go/net/file.go \
go/net/hosts.go \
+ go/net/interface.go \
+ $(go_net_interface_file) \
go/net/ip.go \
go/net/iprawsock.go \
+ go/net/iprawsock_posix.go \
go/net/ipsock.go \
- go/net/lookup.go \
+ go/net/ipsock_posix.go \
+ go/net/lookup_unix.go \
go/net/net.go \
go/net/parse.go \
go/net/pipe.go \
go/net/port.go \
+ $(go_net_sendfile_file) \
go/net/sock.go \
$(go_net_sock_file) \
go/net/tcpsock.go \
+ go/net/tcpsock_posix.go \
go/net/udpsock.go \
- go/net/unixsock.go
+ go/net/udpsock_posix.go \
+ go/net/unixsock.go \
+ go/net/unixsock_posix.go
go_netchan_files = \
go/netchan/common.go \
@@ -766,11 +833,14 @@ go_os_files = \
go/os/file_unix.go \
go/os/getwd.go \
go/os/path.go \
+ go/os/path_unix.go \
go/os/proc.go \
go/os/stat.go \
+ go/os/str.go \
$(go_os_sys_file) \
go/os/time.go \
- go/os/types.go
+ go/os/types.go \
+ signal_unix.go
go_patch_files = \
go/patch/apply.go \
@@ -874,8 +944,12 @@ go_tabwriter_files = \
go/tabwriter/tabwriter.go
go_template_files = \
- go/template/format.go \
- go/template/template.go
+ go/template/doc.go \
+ go/template/exec.go \
+ go/template/funcs.go \
+ go/template/helper.go \
+ go/template/parse.go \
+ go/template/set.go
go_testing_files = \
go/testing/benchmark.go \
@@ -885,8 +959,10 @@ go_time_files = \
go/time/format.go \
go/time/sleep.go \
go/time/sys.go \
+ go/time/sys_posix.go \
go/time/tick.go \
go/time/time.go \
+ go/time/zoneinfo_posix.go \
go/time/zoneinfo_unix.go
go_try_files = \
@@ -895,9 +971,13 @@ go_try_files = \
go_unicode_files = \
go/unicode/casetables.go \
go/unicode/digit.go \
+ go/unicode/graphic.go \
go/unicode/letter.go \
go/unicode/tables.go
+go_url_files = \
+ go/url/url.go
+
go_utf16_files = \
go/utf16/utf16.go
@@ -911,6 +991,7 @@ go_websocket_files = \
go/websocket/websocket.go
go_xml_files = \
+ go/xml/marshal.go \
go/xml/read.go \
go/xml/xml.go
@@ -921,7 +1002,8 @@ go_archive_tar_files = \
go_archive_zip_files = \
go/archive/zip/reader.go \
- go/archive/zip/struct.go
+ go/archive/zip/struct.go \
+ go/archive/zip/writer.go
go_compress_bzip2_files = \
go/compress/bzip2/bit_reader.go \
@@ -1010,7 +1092,8 @@ go_crypto_openpgp_files = \
go/crypto/openpgp/write.go
go_crypto_rand_files = \
go/crypto/rand/rand.go \
- go/crypto/rand/rand_unix.go
+ go/crypto/rand/rand_unix.go \
+ go/crypto/rand/util.go
go_crypto_rc4_files = \
go/crypto/rc4/rc4.go
go_crypto_ripemd160_files = \
@@ -1054,6 +1137,8 @@ go_crypto_xtea_files = \
go_crypto_openpgp_armor_files = \
go/crypto/openpgp/armor/armor.go \
go/crypto/openpgp/armor/encode.go
+go_crypto_openpgp_elgamal_files = \
+ go/crypto/openpgp/elgamal/elgamal.go
go_crypto_openpgp_error_files = \
go/crypto/openpgp/error/error.go
go_crypto_openpgp_packet_files = \
@@ -1072,6 +1157,9 @@ go_crypto_openpgp_packet_files = \
go_crypto_openpgp_s2k_files = \
go/crypto/openpgp/s2k/s2k.go
+go_crypto_x509_pkix_files = \
+ go/crypto/x509/pkix/pkix.go
+
go_debug_dwarf_files = \
go/debug/dwarf/buf.go \
go/debug/dwarf/const.go \
@@ -1092,11 +1180,6 @@ 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 = \
@@ -1109,30 +1192,39 @@ 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_exp_gui_files = \
+ go/exp/gui/gui.go
+go_exp_norm_files = \
+ go/exp/norm/composition.go \
+ go/exp/norm/forminfo.go \
+ go/exp/norm/normalize.go \
+ go/exp/norm/tables.go \
+ go/exp/norm/trie.go
+go_exp_regexp_files = \
+ go/exp/regexp/exec.go \
+ go/exp/regexp/regexp.go
+
+go_exp_gui_x11_files = \
+ go/exp/gui/x11/auth.go \
+ go/exp/gui/x11/conn.go
+
+go_exp_template_html_files = \
+ go/exp/template/html/context.go \
+ go/exp/template/html/escape.go
+
+go_exp_regexp_syntax_files = \
+ go/exp/regexp/syntax/compile.go \
+ go/exp/regexp/syntax/parse.go \
+ go/exp/regexp/syntax/perl_groups.go \
+ go/exp/regexp/syntax/prog.go \
+ go/exp/regexp/syntax/regexp.go \
+ go/exp/regexp/syntax/simplify.go
go_go_ast_files = \
go/go/ast/ast.go \
@@ -1141,6 +1233,11 @@ go_go_ast_files = \
go/go/ast/resolve.go \
go/go/ast/scope.go \
go/go/ast/walk.go
+go_go_build_files = \
+ go/go/build/build.go \
+ go/go/build/dir.go \
+ go/go/build/path.go \
+ syslist.go
go_go_doc_files = \
go/go/doc/comment.go \
go/go/doc/doc.go
@@ -1162,6 +1259,7 @@ go_go_typechecker_files = \
go/go/typechecker/typechecker.go \
go/go/typechecker/universe.go
go_go_types_files = \
+ go/go/types/check.go \
go/go/types/const.go \
go/go/types/exportdata.go \
go/go/types/gcimporter.go \
@@ -1171,7 +1269,8 @@ go_go_types_files = \
go_hash_adler32_files = \
go/hash/adler32/adler32.go
go_hash_crc32_files = \
- go/hash/crc32/crc32.go
+ go/hash/crc32/crc32.go \
+ go/hash/crc32/crc32_generic.go
go_hash_crc64_files = \
go/hash/crc64/crc64.go
go_hash_fnv_files = \
@@ -1189,7 +1288,15 @@ go_http_httptest_files = \
go_http_pprof_files = \
go/http/pprof/pprof.go
go_http_spdy_files = \
- go/http/spdy/protocol.go
+ go/http/spdy/read.go \
+ go/http/spdy/types.go \
+ go/http/spdy/write.go
+
+go_image_bmp_files = \
+ go/image/bmp/reader.go
+
+go_image_draw_files = \
+ go/image/draw/draw.go
go_image_gif_files = \
go/image/gif/reader.go
@@ -1223,7 +1330,8 @@ go_io_ioutil_files = \
go_mime_multipart_files = \
go/mime/multipart/formdata.go \
- go/mime/multipart/multipart.go
+ go/mime/multipart/multipart.go \
+ go/mime/multipart/writer.go
go_net_dict_files = \
go/net/dict/dict.go
@@ -1235,6 +1343,12 @@ go_net_textproto_files = \
go/net/textproto/textproto.go \
go/net/textproto/writer.go
+go_old_template_files = \
+ go/old/template/doc.go \
+ go/old/template/execute.go \
+ go/old/template/format.go \
+ go/old/template/parse.go
+
go_os_inotify_files = \
go/os/inotify/inotify_linux.go
@@ -1243,8 +1357,7 @@ go_os_user_files = \
go/os/user/lookup_unix.go
go_os_signal_files = \
- go/os/signal/signal.go \
- unix.go
+ go/os/signal/signal.go
go_path_filepath_files = \
go/path/filepath/match.go \
@@ -1260,6 +1373,12 @@ go_runtime_debug_files = \
go_runtime_pprof_files = \
go/runtime/pprof/pprof.go
+go_template_parse_files = \
+ go/template/parse/lex.go \
+ go/template/parse/node.go \
+ go/template/parse/parse.go \
+ go/template/parse/set.go
+
go_sync_atomic_files = \
go/sync/atomic/doc.go
go_sync_atomic_c_files = \
@@ -1391,6 +1510,13 @@ else # !LIBGO_IS_SOLARIS
syscall_uname_file = syscalls/syscall_uname.go
endif
+# Support for netlink sockets and messages.
+if LIBGO_IS_LINUX
+syscall_netlink_file = syscalls/netlink_linux.go
+else
+syscall_netlink_file =
+endif
+
syscall_arch.go: s-syscall_arch; @true
s-syscall_arch: Makefile
rm -f syscall_arch.go.tmp
@@ -1407,6 +1533,7 @@ go_syscall_files = \
$(syscall_exec_os_file) \
$(syscall_wait_file) \
$(syscall_filesize_file) \
+ $(syscall_netlink_file) \
$(syscall_stat_file) \
$(syscall_sleep_file) \
syscalls/socket.go \
@@ -1439,6 +1566,7 @@ libgo_go_objs = \
bytes/index.lo \
cmath/cmath.lo \
crypto/crypto.lo \
+ csv/csv.lo \
ebnf/ebnf.lo \
exec/exec.lo \
expvar/expvar.lo \
@@ -1453,6 +1581,7 @@ libgo_go_objs = \
json/json.lo \
log/log.lo \
math/math.lo \
+ mail/mail.lo \
mime/mime.lo \
net/net.lo \
netchan/netchan.lo \
@@ -1477,6 +1606,7 @@ libgo_go_objs = \
time/time.lo \
try/try.lo \
unicode/unicode.lo \
+ url/url.lo \
utf16/utf16.lo \
utf8/utf8.lo \
websocket/websocket.lo \
@@ -1518,27 +1648,32 @@ libgo_go_objs = \
crypto/x509.lo \
crypto/xtea.lo \
crypto/openpgp/armor.lo \
+ crypto/openpgp/elgamal.lo \
crypto/openpgp/error.lo \
crypto/openpgp/packet.lo \
crypto/openpgp/s2k.lo \
+ crypto/x509/pkix.lo \
debug/dwarf.lo \
debug/elf.lo \
debug/gosym.lo \
debug/macho.lo \
debug/pe.lo \
- 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 \
+ exp/gui.lo \
+ exp/norm.lo \
+ exp/regexp.lo \
+ exp/gui/x11.lo \
+ exp/regexp/syntax.lo \
+ exp/template/html.lo \
go/ast.lo \
+ go/build.lo \
go/doc.lo \
go/parser.lo \
go/printer.lo \
@@ -1555,6 +1690,8 @@ libgo_go_objs = \
http/httptest.lo \
http/pprof.lo \
http/spdy.lo \
+ image/bmp.lo \
+ image/draw.lo \
image/gif.lo \
image/jpeg.lo \
image/png.lo \
@@ -1565,6 +1702,7 @@ libgo_go_objs = \
mime/multipart.lo \
net/dict.lo \
net/textproto.lo \
+ old/template.lo \
$(os_lib_inotify_lo) \
os/user.lo \
os/signal.lo \
@@ -1576,6 +1714,7 @@ libgo_go_objs = \
sync/atomic_c.lo \
syscalls/syscall.lo \
syscalls/errno.lo \
+ template/parse.lo \
testing/testing.lo \
testing/iotest.lo \
testing/quick.lo \
@@ -1647,18 +1786,6 @@ CHECK = \
fi; \
fi
-# Check a package that is only tested if GCCGO_RUN_ALL_TESTS is set.
-CHECK_ON_REQUEST = \
- if test "$$GCCGO_RUN_ALL_TESTS" != ""; then \
- $(CHECK); \
- else \
- rm -f $@-testsum $@-testlog; \
- echo "Set GCCGO_RUN_ALL_TESTS in environment to run $(@D) test" > $@-testlog; \
- echo "UNTESTED: $(@D)" >> $@-testlog; \
- echo "UNTESTED: $(@D)"; \
- echo "UNTESTED: $(@D)" > $@-testsum; \
- fi
-
# Build all packages before checking any.
CHECK_DEPS = libgo.la libgobegin.a \
$(toolexeclibgo_DATA) \
@@ -1685,14 +1812,15 @@ CHECK_DEPS = libgo.la libgobegin.a \
$(toolexeclibgosync_DATA) \
$(toolexeclibgotesting_DATA)
-asn1/asn1.lo: $(go_asn1_files) bytes.gox fmt.gox io.gox os.gox reflect.gox \
- strconv.gox strings.gox time.gox
+asn1/asn1.lo: $(go_asn1_files) big.gox 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 os.gox
+big/big.lo: $(go_big_files) encoding/binary.gox fmt.gox io.gox os.gox \
+ rand.gox strings.gox
$(BUILDPACKAGE)
big/check: $(CHECK_DEPS)
@$(CHECK)
@@ -1724,6 +1852,13 @@ crypto/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/check
+csv/csv.lo: $(go_csv_files) bufio.gox bytes.gox fmt.gox io.gox os.gox \
+ strings.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+csv/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: csv/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)
@@ -1731,7 +1866,8 @@ ebnf/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: ebnf/check
-exec/exec.lo: $(go_exec_files) os.gox strconv.gox strings.gox
+exec/exec.lo: $(go_exec_files) bytes.gox io.gox os.gox strconv.gox \
+ strings.gox syscall.gox
$(BUILDPACKAGE)
exec/check: $(CHECK_DEPS)
@$(CHECK)
@@ -1779,11 +1915,11 @@ html/check: $(CHECK_DEPS)
.PHONY: html/check
http/http.lo: $(go_http_files) bufio.gox bytes.gox compress/gzip.gox \
- container/vector.gox crypto/rand.gox crypto/tls.gox \
- encoding/base64.gox fmt.gox io.gox io/ioutil.gox log.gox \
+ crypto/rand.gox crypto/tls.gox encoding/base64.gox \
+ encoding/binary.gox fmt.gox io.gox io/ioutil.gox log.gox \
mime.gox mime/multipart.gox net.gox net/textproto.gox os.gox \
- path.gox path/filepath.gox sort.gox strconv.gox strings.gox \
- sync.gox time.gox utf8.gox
+ path.gox path/filepath.gox runtime/debug.gox sort.gox \
+ strconv.gox strings.gox sync.gox time.gox url.gox utf8.gox
$(BUILDPACKAGE)
http/check: $(CHECK_DEPS)
@$(CHECK)
@@ -1801,10 +1937,9 @@ io/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: io/check
-json/json.lo: $(go_json_files) bytes.gox container/vector.gox \
- encoding/base64.gox fmt.gox io.gox math.gox os.gox \
- reflect.gox runtime.gox strconv.gox strings.gox unicode.gox \
- utf16.gox utf8.gox
+json/json.lo: $(go_json_files) bytes.gox encoding/base64.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)
@@ -1823,6 +1958,14 @@ math/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: math/check
+mail/mail.lo: $(go_mail_files) bufio.gox bytes.gox encoding/base64.gox \
+ fmt.gox io.gox io/ioutil.gox log.gox net/textproto.gox os.gox \
+ strconv.gox strings.gox time.gox
+ $(BUILDPACKAGE)
+mail/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: mail/check
+
mime/mime.lo: $(go_mime_files) bufio.gox bytes.gox fmt.gox os.gox strings.gox \
sync.gox unicode.gox
$(BUILDPACKAGE)
@@ -1835,7 +1978,7 @@ net/net.lo: $(go_net_files) bytes.gox fmt.gox io.gox os.gox rand.gox \
syscall.gox time.gox
$(BUILDPACKAGE)
net/check: $(CHECK_DEPS)
- @$(CHECK_ON_REQUEST)
+ @$(CHECK)
.PHONY: net/check
netchan/netchan.lo: $(go_netchan_files) gob.gox io.gox log.gox net.gox os.gox \
@@ -1851,6 +1994,10 @@ os/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: os/check
+signal_unix.go: $(srcdir)/go/os/mkunixsignals.sh sysinfo.go
+ $(SHELL) $(srcdir)/go/os/mkunixsignals.sh sysinfo.go > $@.tmp
+ mv -f $@.tmp $@
+
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
@@ -1913,7 +2060,7 @@ smtp/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: smtp/check
-sort/sort.lo: $(go_sort_files)
+sort/sort.lo: $(go_sort_files) math.gox
$(BUILDPACKAGE)
sort/check: $(CHECK_DEPS)
@$(CHECK)
@@ -1943,7 +2090,7 @@ syslog/syslog.lo: $(go_syslog_files) fmt.gox log.gox net.gox os.gox syscall.gox
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_ON_REQUEST)
+ @$(CHECK)
.PHONY: syslog/check
tabwriter/tabwriter.lo: $(go_tabwriter_files) bytes.gox io.gox os.gox utf8.gox
@@ -1952,15 +2099,17 @@ 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
+template/template.lo: $(go_template_files) bytes.gox fmt.gox io.gox \
+ io/ioutil.gox os.gox path/filepath.gox reflect.gox \
+ runtime.gox strings.gox template/parse.gox unicode.gox \
+ url.gox utf8.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 runtime/pprof.gox time.gox
+ runtime.gox runtime/pprof.gox strings.gox strconv.gox time.gox
$(BUILDPACKAGE)
testing/check: $(CHECK_DEPS)
@$(CHECK)
@@ -1985,6 +2134,12 @@ unicode/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: unicode/check
+url/url.lo: $(go_url_files) os.gox strconv.gox strings.gox
+ $(BUILDPACKAGE)
+url/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: url/check
+
utf16/utf16.lo: $(go_utf16_files) unicode.gox
$(BUILDPACKAGE)
utf16/check: $(CHECK_DEPS)
@@ -1998,9 +2153,8 @@ utf8/check: $(CHECK_DEPS)
.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
+ crypto/md5.gox crypto/tls.gox encoding/binary.gox fmt.gox \
+ http.gox io.gox net.gox os.gox rand.gox strings.gox url.gox
$(BUILDPACKAGE)
websocket/check: $(CHECK_DEPS)
@$(CHECK)
@@ -2021,9 +2175,9 @@ archive/tar/check: $(CHECK_DEPS)
@$(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 io/ioutil.gox os.gox
+archive/zip.lo: $(go_archive_zip_files) bufio.gox compress/flate.gox \
+ encoding/binary.gox hash.gox hash/crc32.gox \
+ encoding/binary.gox io.gox io/ioutil.gox os.gox time.gox
$(BUILDPACKAGE)
archive/zip/check: $(CHECK_DEPS)
@$(MKDIR_P) archive/zip
@@ -2176,25 +2330,27 @@ crypto/md5/check: $(CHECK_DEPS)
.PHONY: crypto/md5/check
crypto/ocsp.lo: $(go_crypto_ocsp_files) asn1.gox crypto.gox crypto/rsa.gox \
- crypto/sha1.gox crypto/x509.gox os.gox time.gox
+ crypto/sha1.gox crypto/x509.gox crypto/x509/pkix.gox os.gox \
+ time.gox
$(BUILDPACKAGE)
crypto/ocsp/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/ocsp
@$(CHECK)
.PHONY: crypto/ocsp/check
-crypto/openpgp.lo: $(go_crypto_openpgp_files) crypto.gox crypto/dsa.gox \
+crypto/openpgp.lo: $(go_crypto_openpgp_files) crypto.gox \
crypto/openpgp/armor.gox crypto/openpgp/error.gox \
- crypto/openpgp/packet.gox crypto/rsa.gox crypto/sha256.gox \
- hash.gox io.gox os.gox strconv.gox time.gox
+ crypto/openpgp/packet.gox crypto/openpgp/s2k.gox \
+ crypto/rand.gox crypto/rsa.gox crypto/sha256.gox hash.gox \
+ io.gox os.gox strconv.gox time.gox
$(BUILDPACKAGE)
crypto/openpgp/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp
@$(CHECK)
.PHONY: crypto/openpgp/check
-crypto/rand.lo: $(go_crypto_rand_files) bufio.gox crypto/aes.gox io.gox \
- os.gox sync.gox time.gox
+crypto/rand.lo: $(go_crypto_rand_files) big.gox bufio.gox crypto/aes.gox \
+ io.gox os.gox sync.gox time.gox
$(BUILDPACKAGE)
crypto/rand/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/rand
@@ -2215,8 +2371,9 @@ crypto/ripemd160/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/ripemd160/check
-crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/sha1.gox \
- crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox
+crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/rand.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
@@ -2255,9 +2412,9 @@ crypto/tls.lo: $(go_crypto_tls_files) big.gox bytes.gox crypto.gox \
crypto/aes.gox crypto/cipher.gox crypto/elliptic.gox \
crypto/hmac.gox crypto/md5.gox crypto/rand.gox crypto/rc4.gox \
crypto/rsa.gox crypto/sha1.gox crypto/subtle.gox \
- crypto/x509.gox encoding/pem.gox hash.gox io.gox \
- io/ioutil.gox net.gox os.gox strconv.gox strings.gox sync.gox \
- time.gox
+ crypto/x509.gox crypto/x509/pkix.gox encoding/pem.gox \
+ hash.gox io.gox io/ioutil.gox net.gox os.gox strconv.gox \
+ strings.gox sync.gox time.gox
$(BUILDPACKAGE)
crypto/tls/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/tls
@@ -2271,9 +2428,9 @@ crypto/twofish/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/twofish/check
-crypto/x509.lo: $(go_crypto_x509_files) asn1.gox big.gox bytes.gox \
- container/vector.gox crypto.gox crypto/rsa.gox \
- crypto/sha1.gox encoding/pem.gox hash.gox os.gox strings.gox \
+crypto/x509.lo: $(go_crypto_x509_files) asn1.gox big.gox bytes.gox crypto.gox \
+ crypto/dsa.gox crypto/rsa.gox crypto/sha1.gox \
+ crypto/x509/pkix.gox encoding/pem.gox os.gox strings.gox \
time.gox
$(BUILDPACKAGE)
crypto/x509/check: $(CHECK_DEPS)
@@ -2296,6 +2453,14 @@ crypto/openpgp/armor/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/openpgp/armor/check
+crypto/openpgp/elgamal.lo: $(go_crypto_openpgp_elgamal_files) big.gox \
+ crypto/rand.gox crypto/subtle.gox io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/openpgp/elgamal/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/openpgp/elgamal
+ @$(CHECK)
+.PHONY: crypto/openpgp/elgamal/check
+
crypto/openpgp/error.lo: $(go_crypto_openpgp_error_files) strconv.gox
$(BUILDPACKAGE)
crypto/openpgp/error/check: $(CHECK_DEPS)
@@ -2306,9 +2471,10 @@ crypto/openpgp/error/check: $(CHECK_DEPS)
crypto/openpgp/packet.lo: $(go_crypto_openpgp_packet_files) big.gox bytes.gox \
compress/flate.gox compress/zlib.gox crypto.gox \
crypto/aes.gox crypto/cast5.gox crypto/cipher.gox \
- crypto/dsa.gox crypto/openpgp/error.gox \
- crypto/openpgp/s2k.gox crypto/rand.gox crypto/rsa.gox \
- crypto/sha1.gox crypto/subtle.gox encoding/binary.gox fmt.gox \
+ crypto/dsa.gox crypto/openpgp/elgamal.gox \
+ crypto/openpgp/error.gox crypto/openpgp/s2k.gox \
+ crypto/rand.gox crypto/rsa.gox crypto/sha1.gox \
+ crypto/subtle.gox encoding/binary.gox fmt.gox \
hash.gox io.gox io/ioutil.gox os.gox strconv.gox strings.gox
$(BUILDPACKAGE)
crypto/openpgp/packet/check: $(CHECK_DEPS)
@@ -2317,15 +2483,22 @@ crypto/openpgp/packet/check: $(CHECK_DEPS)
.PHONY: crypto/openpgp/packet/check
crypto/openpgp/s2k.lo: $(go_crypto_openpgp_s2k_files) crypto.gox \
- 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
+ crypto/md5.gox crypto/openpgp/error.gox crypto/rand.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
+crypto/x509/pkix.lo: $(go_crypto_x509_pkix_files) asn1.gox big.gox time.gox
+ $(BUILDPACKAGE)
+crypto/x509/pkix/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/x509/pkix
+ @$(CHECK)
+.PHONY: crypto/x509/pkix/check
+
debug/dwarf.lo: $(go_debug_dwarf_files) encoding/binary.gox os.gox strconv.gox
$(BUILDPACKAGE)
debug/dwarf/check: $(CHECK_DEPS)
@@ -2365,15 +2538,6 @@ debug/pe/check: $(CHECK_DEPS)
@$(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)
@@ -2411,20 +2575,13 @@ encoding/git85/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: encoding/git85/check
-encoding/hex.lo: $(go_encoding_hex_files) os.gox strconv.gox
+encoding/hex.lo: $(go_encoding_hex_files) bytes.gox io.gox 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)
@@ -2432,39 +2589,87 @@ encoding/pem/check: $(CHECK_DEPS)
@$(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
+exp/datafmt.lo: $(go_exp_datafmt_files) bytes.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 image/ycbcr.gox os.gox
+exp/gui.lo: $(go_exp_gui_files) image.gox image/draw.gox os.gox
+ $(BUILDPACKAGE)
+exp/gui/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/gui
+ @$(CHECK)
+.PHONY: exp/gui/check
+
+exp/norm.lo: $(go_exp_norm_files) utf8.gox
+ $(BUILDPACKAGE)
+exp/norm/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/norm
+ @$(CHECK)
+.PHONY: exp/norm/check
+
+exp/regexp.lo: $(go_exp_regexp_files) bytes.gox exp/regexp/syntax.gox io.gox \
+ os.gox strings.gox sync.gox utf8.gox
+ $(BUILDPACKAGE)
+exp/regexp/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/regexp
+ @$(CHECK)
+.PHONY: exp/regexp/check
+
+exp/gui/x11.lo: $(go_exp_gui_x11_files) bufio.gox exp/gui.gox image.gox \
+ image/draw.gox io.gox log.gox net.gox os.gox strconv.gox \
+ strings.gox time.gox
+ $(BUILDPACKAGE)
+exp/gui/x11/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/gui/x11
+ @$(CHECK)
+.PHONY: exp/gui/x11/check
+
+exp/regexp/syntax.lo: $(go_exp_regexp_syntax_files) bytes.gox os.gox sort.gox strconv.gox strings.gox unicode.gox utf8.gox
$(BUILDPACKAGE)
-exp/draw/check: $(CHECK_DEPS)
- @$(MKDIR_P) exp/draw
+exp/regexp/syntax/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/regexp/syntax
@$(CHECK)
-.PHONY: exp/draw/check
+.PHONY: exp/regexp/syntax/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
+exp/template/html.lo: $(go_exp_template_html_files) fmt.gox template.gox \
+ template/parse.gox
$(BUILDPACKAGE)
-exp/eval/check: $(CHECK_DEPS)
- @$(MKDIR_P) exp/eval
+exp/template/html/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/template/html
@$(CHECK)
-.PHONY: exp/eval/check
+.PHONY: exp/template/html/check
go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/scanner.gox go/token.gox \
- io.gox os.gox reflect.gox unicode.gox utf8.gox
+ io.gox os.gox reflect.gox strconv.gox unicode.gox utf8.gox
$(BUILDPACKAGE)
go/ast/check: $(CHECK_DEPS)
@$(MKDIR_P) go/ast
@$(CHECK)
.PHONY: go/ast/check
+go/build.lo: $(go_go_build_files) bytes.gox exec.gox fmt.gox go/parser.gox \
+ go/token.gox log.gox os.gox path/filepath.gox regexp.gox \
+ runtime.gox strconv.gox strings.gox runtime.gox
+ $(BUILDPACKAGE)
+go/build/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/build
+ @$(CHECK)
+.PHONY: go/build/check
+
+syslist.go: s-syslist; @true
+s-syslist: Makefile
+ echo '// Generated automatically by make.' >syslist.go.tmp
+ echo 'package build' >>syslist.go.tmp
+ echo 'const goosList = "$(GOOS)"' >>syslist.go.tmp
+ echo 'const goarchList = "$(GOARCH)"' >>syslist.go.tmp
+ $(SHELL) $(srcdir)/../move-if-change syslist.go.tmp syslist.go
+ $(STAMP) $@
+
go/doc.lo: $(go_go_doc_files) go/ast.gox go/token.gox io.gox regexp.gox \
sort.gox strings.gox template.gox
$(BUILDPACKAGE)
@@ -2491,9 +2696,9 @@ go/printer/check: $(CHECK_DEPS)
@$(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/filepath.gox sort.gox \
- strconv.gox unicode.gox utf8.gox
+go/scanner.lo: $(go_go_scanner_files) bytes.gox fmt.gox go/token.gox io.gox \
+ os.gox path/filepath.gox sort.gox strconv.gox unicode.gox \
+ utf8.gox
$(BUILDPACKAGE)
go/scanner/check: $(CHECK_DEPS)
@$(MKDIR_P) go/scanner
@@ -2517,7 +2722,7 @@ go/typechecker/check: $(CHECK_DEPS)
go/types.lo: $(go_go_types_files) big.gox bufio.gox fmt.gox go/ast.gox \
go/token.gox io.gox os.gox path/filepath.gox runtime.gox \
- scanner.gox strconv.gox strings.gox
+ scanner.gox sort.gox strconv.gox strings.gox
$(BUILDPACKAGE)
go/types/check: $(CHECK_DEPS)
@$(MKDIR_P) go/types
@@ -2531,7 +2736,7 @@ hash/adler32/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: hash/adler32/check
-hash/crc32.lo: $(go_hash_crc32_files) hash.gox os.gox
+hash/crc32.lo: $(go_hash_crc32_files) hash.gox os.gox sync.gox
$(BUILDPACKAGE)
hash/crc32/check: $(CHECK_DEPS)
@$(MKDIR_P) hash/crc32
@@ -2552,10 +2757,9 @@ hash/fnv/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: hash/fnv/check
-http/cgi.lo: $(go_http_cgi_files) bufio.gox bytes.gox crypto/tls.gox \
- exec.gox fmt.gox http.gox net.gox io.gox io/ioutil.gox \
- log.gox os.gox path/filepath.gox regexp.gox strconv.gox \
- strings.gox
+http/cgi.lo: $(go_http_cgi_files) bufio.gox crypto/tls.gox exec.gox fmt.gox \
+ http.gox net.gox io.gox io/ioutil.gox log.gox os.gox \
+ path/filepath.gox regexp.gox strconv.gox strings.gox url.gox
$(BUILDPACKAGE)
http/cgi/check: $(CHECK_DEPS)
@$(MKDIR_P) http/cgi
@@ -2572,7 +2776,8 @@ http/fcgi/check: $(CHECK_DEPS)
.PHONY: http/fcgi/check
http/httptest.lo: $(go_http_httptest_files) bytes.gox crypto/rand.gox \
- crypto/tls.gox fmt.gox http.gox net.gox os.gox time.gox
+ crypto/tls.gox flag.gox fmt.gox http.gox net.gox os.gox \
+ time.gox
$(BUILDPACKAGE)
http/httptest/check: $(CHECK_DEPS)
@$(MKDIR_P) http/httptest
@@ -2596,6 +2801,20 @@ http/spdy/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: http/spdy/check
+image/bmp.lo: $(go_image_bmp_files) image.gox io.gox os.gox
+ $(BUILDPACKAGE)
+image/bmp/check: $(CHECK_DEPS)
+ @$(MKDIR_P) image/bmp
+ @$(CHECK)
+.PHONY: image/bmp/check
+
+image/draw.lo: $(go_image_draw_files) image.gox image/ycbcr.gox
+ $(BUILDPACKAGE)
+image/draw/check: $(CHECK_DEPS)
+ @$(MKDIR_P) image/draw
+ @$(CHECK)
+.PHONY: image/draw/check
+
image/gif.lo: $(go_image_gif_files) bufio.gox compress/lzw.gox fmt.gox \
image.gox io.gox os.gox
$(BUILDPACKAGE)
@@ -2651,28 +2870,36 @@ io/ioutil/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: io/ioutil/check
-mime/multipart.lo: $(go_mime_multipart_files) bufio.gox bytes.gox fmt.gox \
- io.gox io/ioutil.gox mime.gox net/textproto.gox os.gox \
- regexp.gox
+mime/multipart.lo: $(go_mime_multipart_files) bufio.gox bytes.gox \
+ crypto/rand.gox fmt.gox io.gox io/ioutil.gox mime.gox \
+ net/textproto.gox os.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
+net/dict.lo: $(go_net_dict_files) 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
+net/textproto.lo: $(go_net_textproto_files) bufio.gox bytes.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
+old/template.lo: $(go_old_template_files) bytes.gox fmt.gox io.gox \
+ io/ioutil.gox os.gox reflect.gox strconv.gox strings.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+old/template/check: $(CHECK_DEPS)
+ @$(MKDIR_P) old/template
+ @$(CHECK)
+.PHONY: old/template/check
+
os/inotify.lo: $(go_os_inotify_files) fmt.gox os.gox strings.gox syscall.gox
$(BUILDPACKAGE)
os/inotify/check: $(CHECK_DEPS)
@@ -2688,19 +2915,15 @@ os/user/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: os/user/check
-os/signal.lo: $(go_os_signal_files) runtime.gox strconv.gox
+os/signal.lo: $(go_os_signal_files) os.gox runtime.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 $@
-
-path/filepath.lo: $(go_path_filepath_files) bytes.gox os.gox sort.gox \
- strings.gox utf8.gox
+path/filepath.lo: $(go_path_filepath_files) bytes.gox os.gox runtime.gox \
+ sort.gox strings.gox utf8.gox
$(BUILDPACKAGE)
path/filepath/check: $(CHECK_DEPS)
@$(MKDIR_P) path/filepath
@@ -2740,6 +2963,14 @@ sync/atomic/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: sync/atomic/check
+template/parse.lo: $(go_template_parse_files) bytes.gox fmt.gox os.gox \
+ runtime.gox strconv.gox strings.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+template/parse/check: $(CHECK_DEPS)
+ @$(MKDIR_P) template/parse
+ @$(CHECK)
+.PHONY: template/parse/check
+
testing/iotest.lo: $(go_testing_iotest_files) io.gox log.gox os.gox
$(BUILDPACKAGE)
testing/iotest/check: $(CHECK_DEPS)
@@ -2791,6 +3022,8 @@ cmath.gox: cmath/cmath.lo
$(BUILDGOX)
crypto.gox: crypto/crypto.lo
$(BUILDGOX)
+csv.gox: csv/csv.lo
+ $(BUILDGOX)
ebnf.gox: ebnf/ebnf.lo
$(BUILDGOX)
exec.gox: exec/exec.lo
@@ -2819,6 +3052,8 @@ log.gox: log/log.lo
$(BUILDGOX)
math.gox: math/math.lo
$(BUILDGOX)
+mail.gox: mail/mail.lo
+ $(BUILDGOX)
mime.gox: mime/mime.lo
$(BUILDGOX)
net.gox: net/net.lo
@@ -2869,6 +3104,8 @@ try.gox: try/try.lo
$(BUILDGOX)
unicode.gox: unicode/unicode.lo
$(BUILDGOX)
+url.gox: url/url.lo
+ $(BUILDGOX)
utf16.gox: utf16/utf16.lo
$(BUILDGOX)
utf8.gox: utf8/utf8.lo
@@ -2956,6 +3193,8 @@ crypto/xtea.gox: crypto/xtea.lo
crypto/openpgp/armor.gox: crypto/openpgp/armor.lo
$(BUILDGOX)
+crypto/openpgp/elgamal.gox: crypto/openpgp/elgamal.lo
+ $(BUILDGOX)
crypto/openpgp/error.gox: crypto/openpgp/error.lo
$(BUILDGOX)
crypto/openpgp/packet.gox: crypto/openpgp/packet.lo
@@ -2963,6 +3202,9 @@ crypto/openpgp/packet.gox: crypto/openpgp/packet.lo
crypto/openpgp/s2k.gox: crypto/openpgp/s2k.lo
$(BUILDGOX)
+crypto/x509/pkix.gox: crypto/x509/pkix.lo
+ $(BUILDGOX)
+
debug/dwarf.gox: debug/dwarf.lo
$(BUILDGOX)
debug/elf.gox: debug/elf.lo
@@ -2973,8 +3215,6 @@ 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)
@@ -2988,20 +3228,31 @@ 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
+exp/gui.gox: exp/gui.lo
+ $(BUILDGOX)
+exp/norm.gox: exp/norm.lo
+ $(BUILDGOX)
+exp/regexp.gox: exp/regexp.lo
+ $(BUILDGOX)
+
+exp/gui/x11.gox: exp/gui/x11.lo
+ $(BUILDGOX)
+
+exp/regexp/syntax.gox: exp/regexp/syntax.lo
$(BUILDGOX)
-exp/eval.gox: exp/eval.lo
+
+exp/template/html.gox: exp/template/html.lo
$(BUILDGOX)
go/ast.gox: go/ast.lo
$(BUILDGOX)
+go/build.gox: go/build.lo
+ $(BUILDGOX)
go/doc.gox: go/doc.lo
$(BUILDGOX)
go/parser.gox: go/parser.lo
@@ -3037,6 +3288,10 @@ http/pprof.gox: http/pprof.lo
http/spdy.gox: http/spdy.lo
$(BUILDGOX)
+image/bmp.gox: image/bmp.lo
+ $(BUILDGOX)
+image/draw.gox: image/draw.lo
+ $(BUILDGOX)
image/gif.gox: image/gif.lo
$(BUILDGOX)
image/jpeg.gox: image/jpeg.lo
@@ -3062,6 +3317,9 @@ net/dict.gox: net/dict.lo
net/textproto.gox: net/textproto.lo
$(BUILDGOX)
+old/template.gox: old/template.lo
+ $(BUILDGOX)
+
os/inotify.gox: os/inotify.lo
$(BUILDGOX)
os/user.gox: os/user.lo
@@ -3083,6 +3341,9 @@ runtime/pprof.gox: runtime/pprof.lo
sync/atomic.gox: sync/atomic.lo
$(BUILDGOX)
+template/parse.gox: template/parse.lo
+ $(BUILDGOX)
+
testing/iotest.gox: testing/iotest.lo
$(BUILDGOX)
testing/quick.gox: testing/quick.lo
@@ -3103,6 +3364,7 @@ TEST_PACKAGES = \
bufio/check \
bytes/check \
cmath/check \
+ csv/check \
ebnf/check \
exec/check \
expvar/check \
@@ -3111,10 +3373,12 @@ TEST_PACKAGES = \
gob/check \
html/check \
http/check \
+ image/check \
io/check \
json/check \
log/check \
math/check \
+ mail/check \
mime/check \
net/check \
netchan/check \
@@ -3138,6 +3402,7 @@ TEST_PACKAGES = \
time/check \
try/check \
unicode/check \
+ url/check \
utf16/check \
utf8/check \
websocket/check \
@@ -3179,6 +3444,7 @@ TEST_PACKAGES = \
crypto/x509/check \
crypto/xtea/check \
crypto/openpgp/armor/check \
+ crypto/openpgp/elgamal/check \
crypto/openpgp/packet/check \
crypto/openpgp/s2k/check \
debug/dwarf/check \
@@ -3191,12 +3457,14 @@ TEST_PACKAGES = \
encoding/binary/check \
encoding/git85/check \
encoding/hex/check \
- encoding/line/check \
encoding/pem/check \
exp/datafmt/check \
- exp/draw/check \
- exp/eval/check \
+ exp/norm/check \
+ exp/regexp/check \
+ exp/regexp/syntax/check \
+ exp/template/html/check \
go/ast/check \
+ $(go_build_check_omitted_since_it_calls_6g) \
go/parser/check \
go/printer/check \
go/scanner/check \
@@ -3210,6 +3478,7 @@ TEST_PACKAGES = \
http/cgi/check \
http/fcgi/check \
http/spdy/check \
+ image/draw/check \
image/jpeg/check \
image/png/check \
image/tiff/check \
@@ -3218,12 +3487,14 @@ TEST_PACKAGES = \
io/ioutil/check \
mime/multipart/check \
net/textproto/check \
+ old/template/check \
$(os_inotify_check) \
os/user/check \
os/signal/check \
path/filepath/check \
rpc/jsonrpc/check \
sync/atomic/check \
+ template/parse/check \
testing/quick/check \
testing/script/check
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 42a160f3cf5..41ffe7c7230 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -98,9 +98,13 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibgocontainerdir)" \
"$(DESTDIR)$(toolexeclibgocryptodir)" \
"$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" \
+ "$(DESTDIR)$(toolexeclibgocryptox509dir)" \
"$(DESTDIR)$(toolexeclibgodebugdir)" \
"$(DESTDIR)$(toolexeclibgoencodingdir)" \
"$(DESTDIR)$(toolexeclibgoexpdir)" \
+ "$(DESTDIR)$(toolexeclibgoexpguidir)" \
+ "$(DESTDIR)$(toolexeclibgoexpregexpdir)" \
+ "$(DESTDIR)$(toolexeclibgoexptemplatedir)" \
"$(DESTDIR)$(toolexeclibgogodir)" \
"$(DESTDIR)$(toolexeclibgohashdir)" \
"$(DESTDIR)$(toolexeclibgohttpdir)" \
@@ -109,11 +113,13 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibgoiodir)" \
"$(DESTDIR)$(toolexeclibgomimedir)" \
"$(DESTDIR)$(toolexeclibgonetdir)" \
+ "$(DESTDIR)$(toolexeclibgoolddir)" \
"$(DESTDIR)$(toolexeclibgoosdir)" \
"$(DESTDIR)$(toolexeclibgopathdir)" \
"$(DESTDIR)$(toolexeclibgorpcdir)" \
"$(DESTDIR)$(toolexeclibgoruntimedir)" \
"$(DESTDIR)$(toolexeclibgosyncdir)" \
+ "$(DESTDIR)$(toolexeclibgotemplatedir)" \
"$(DESTDIR)$(toolexeclibgotestingdir)"
LIBRARIES = $(toolexeclib_LIBRARIES)
ARFLAGS = cru
@@ -125,18 +131,18 @@ 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 crypto/crypto.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/sync.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 \
+ csv/csv.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 mail/mail.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/sync.lo syslog/syslog.lo syslog/syslog_c.lo \
+ tabwriter/tabwriter.lo template/template.lo time/time.lo \
+ try/try.lo unicode/unicode.lo url/url.lo utf16/utf16.lo \
+ utf8/utf8.lo websocket/websocket.lo xml/xml.lo archive/tar.lo \
archive/zip.lo compress/bzip2.lo compress/flate.lo \
compress/gzip.lo compress/lzw.lo compress/zlib.lo \
container/heap.lo container/list.lo container/ring.lo \
@@ -148,24 +154,27 @@ am__DEPENDENCIES_2 = asn1/asn1.lo big/big.lo bufio/bufio.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/packet.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 \
+ crypto/openpgp/elgamal.lo crypto/openpgp/error.lo \
+ crypto/openpgp/packet.lo crypto/openpgp/s2k.lo \
+ crypto/x509/pkix.lo debug/dwarf.lo debug/elf.lo debug/gosym.lo \
+ debug/macho.lo debug/pe.lo encoding/ascii85.lo \
+ encoding/base32.lo encoding/base64.lo encoding/binary.lo \
+ encoding/git85.lo encoding/hex.lo encoding/pem.lo \
+ exp/datafmt.lo exp/gui.lo exp/norm.lo exp/regexp.lo \
+ exp/gui/x11.lo exp/regexp/syntax.lo exp/template/html.lo \
+ go/ast.lo go/build.lo go/doc.lo go/parser.lo go/printer.lo \
go/scanner.lo go/token.lo go/typechecker.lo go/types.lo \
hash/adler32.lo hash/crc32.lo hash/crc64.lo hash/fnv.lo \
http/cgi.lo http/fcgi.lo http/httptest.lo http/pprof.lo \
- http/spdy.lo image/gif.lo image/jpeg.lo image/png.lo \
- image/tiff.lo image/ycbcr.lo index/suffixarray.lo io/ioutil.lo \
- mime/multipart.lo net/dict.lo net/textproto.lo \
+ http/spdy.lo image/bmp.lo image/draw.lo image/gif.lo \
+ image/jpeg.lo image/png.lo image/tiff.lo image/ycbcr.lo \
+ index/suffixarray.lo io/ioutil.lo mime/multipart.lo \
+ net/dict.lo net/textproto.lo old/template.lo \
$(am__DEPENDENCIES_1) os/user.lo os/signal.lo path/filepath.lo \
rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
sync/atomic.lo sync/atomic_c.lo syscalls/syscall.lo \
- syscalls/errno.lo testing/testing.lo testing/iotest.lo \
- testing/quick.lo testing/script.lo
+ syscalls/errno.lo template/parse.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)
@@ -189,7 +198,7 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.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-print.c runtime/go-rand.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 \
@@ -230,22 +239,23 @@ am__objects_3 = go-append.lo go-assert.lo go-assert-interface.lo \
go-make-slice.lo go-map-delete.lo go-map-index.lo \
go-map-len.lo go-map-range.lo go-nanotime.lo go-new-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-setenv.lo go-signal.lo \
- go-strcmp.lo go-string-to-byte-array.lo \
- go-string-to-int-array.lo go-strplus.lo go-strslice.lo \
- go-trampoline.lo go-type-eface.lo go-type-error.lo \
- go-type-identity.lo go-type-interface.lo go-type-string.lo \
- go-typedesc-equal.lo go-typestring.lo go-unreflect.lo \
- go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \
- go-unwind.lo cpuprof.lo mcache.lo mcentral.lo $(am__objects_1) \
- mfinal.lo mfixalloc.lo mgc0.lo mheap.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
+ go-panic-defer.lo go-print.lo go-rand.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-setenv.lo go-signal.lo go-strcmp.lo \
+ go-string-to-byte-array.lo go-string-to-int-array.lo \
+ go-strplus.lo go-strslice.lo go-trampoline.lo go-type-eface.lo \
+ go-type-error.lo go-type-identity.lo go-type-interface.lo \
+ go-type-string.lo go-typedesc-equal.lo go-typestring.lo \
+ go-unreflect.lo go-unsafe-new.lo go-unsafe-newarray.lo \
+ go-unsafe-pointer.lo go-unwind.lo cpuprof.lo mcache.lo \
+ mcentral.lo $(am__objects_1) mfinal.lo mfixalloc.lo mgc0.lo \
+ mheap.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)
libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
@@ -282,14 +292,17 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
$(toolexeclibgocompress_DATA) $(toolexeclibgocontainer_DATA) \
$(toolexeclibgocrypto_DATA) $(toolexeclibgocryptoopenpgp_DATA) \
- $(toolexeclibgodebug_DATA) $(toolexeclibgoencoding_DATA) \
- $(toolexeclibgoexp_DATA) $(toolexeclibgogo_DATA) \
+ $(toolexeclibgocryptox509_DATA) $(toolexeclibgodebug_DATA) \
+ $(toolexeclibgoencoding_DATA) $(toolexeclibgoexp_DATA) \
+ $(toolexeclibgoexpgui_DATA) $(toolexeclibgoexpregexp_DATA) \
+ $(toolexeclibgoexptemplate_DATA) $(toolexeclibgogo_DATA) \
$(toolexeclibgohash_DATA) $(toolexeclibgohttp_DATA) \
$(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \
$(toolexeclibgoio_DATA) $(toolexeclibgomime_DATA) \
- $(toolexeclibgonet_DATA) $(toolexeclibgoos_DATA) \
- $(toolexeclibgopath_DATA) $(toolexeclibgorpc_DATA) \
- $(toolexeclibgoruntime_DATA) $(toolexeclibgosync_DATA) \
+ $(toolexeclibgonet_DATA) $(toolexeclibgoold_DATA) \
+ $(toolexeclibgoos_DATA) $(toolexeclibgopath_DATA) \
+ $(toolexeclibgorpc_DATA) $(toolexeclibgoruntime_DATA) \
+ $(toolexeclibgosync_DATA) $(toolexeclibgotemplate_DATA) \
$(toolexeclibgotesting_DATA)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
@@ -363,7 +376,6 @@ 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@
@@ -559,6 +571,7 @@ toolexeclibgo_DATA = \
bytes.gox \
cmath.gox \
crypto.gox \
+ csv.gox \
ebnf.gox \
exec.gox \
expvar.gox \
@@ -573,6 +586,7 @@ toolexeclibgo_DATA = \
json.gox \
log.gox \
math.gox \
+ mail.gox \
mime.gox \
net.gox \
netchan.gox \
@@ -598,6 +612,7 @@ toolexeclibgo_DATA = \
time.gox \
try.gox \
unicode.gox \
+ url.gox \
utf16.gox \
utf8.gox \
websocket.gox \
@@ -654,18 +669,22 @@ toolexeclibgocrypto_DATA = \
toolexeclibgocryptoopenpgpdir = $(toolexeclibgocryptodir)/openpgp
toolexeclibgocryptoopenpgp_DATA = \
crypto/openpgp/armor.gox \
+ crypto/openpgp/elgamal.gox \
crypto/openpgp/error.gox \
crypto/openpgp/packet.gox \
crypto/openpgp/s2k.gox
+toolexeclibgocryptox509dir = $(toolexeclibgocryptodir)/x509
+toolexeclibgocryptox509_DATA = \
+ crypto/x509/pkix.gox
+
toolexeclibgodebugdir = $(toolexeclibgodir)/debug
toolexeclibgodebug_DATA = \
debug/dwarf.gox \
debug/elf.gox \
debug/gosym.gox \
debug/macho.gox \
- debug/pe.gox \
- debug/proc.gox
+ debug/pe.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
toolexeclibgoencoding_DATA = \
@@ -673,7 +692,6 @@ toolexeclibgoencoding_DATA = \
encoding/base32.gox \
encoding/base64.gox \
encoding/binary.gox \
- encoding/line.gox \
encoding/git85.gox \
encoding/hex.gox \
encoding/pem.gox
@@ -681,12 +699,26 @@ toolexeclibgoencoding_DATA = \
toolexeclibgoexpdir = $(toolexeclibgodir)/exp
toolexeclibgoexp_DATA = \
exp/datafmt.gox \
- exp/draw.gox \
- exp/eval.gox
+ exp/gui.gox \
+ exp/norm.gox \
+ exp/regexp.gox
+
+toolexeclibgoexpguidir = $(toolexeclibgoexpdir)/gui
+toolexeclibgoexpgui_DATA = \
+ exp/gui/x11.gox
+
+toolexeclibgoexpregexpdir = $(toolexeclibgoexpdir)/regexp
+toolexeclibgoexpregexp_DATA = \
+ exp/regexp/syntax.gox
+
+toolexeclibgoexptemplatedir = $(toolexeclibgoexpdir)/template
+toolexeclibgoexptemplate_DATA = \
+ exp/template/html.gox
toolexeclibgogodir = $(toolexeclibgodir)/go
toolexeclibgogo_DATA = \
go/ast.gox \
+ go/build.gox \
go/doc.gox \
go/parser.gox \
go/printer.gox \
@@ -712,6 +744,8 @@ toolexeclibgohttp_DATA = \
toolexeclibgoimagedir = $(toolexeclibgodir)/image
toolexeclibgoimage_DATA = \
+ image/bmp.gox \
+ image/draw.gox \
image/gif.gox \
image/jpeg.gox \
image/png.gox \
@@ -735,6 +769,10 @@ toolexeclibgonet_DATA = \
net/dict.gox \
net/textproto.gox
+toolexeclibgoolddir = $(toolexeclibgodir)/old
+toolexeclibgoold_DATA = \
+ old/template.gox
+
toolexeclibgoosdir = $(toolexeclibgodir)/os
@LIBGO_IS_LINUX_FALSE@os_inotify_gox =
@@ -758,6 +796,10 @@ toolexeclibgoruntime_DATA = \
runtime/debug.gox \
runtime/pprof.gox
+toolexeclibgotemplatedir = $(toolexeclibgodir)/template
+toolexeclibgotemplate_DATA = \
+ template/parse.gox
+
toolexeclibgosyncdir = $(toolexeclibgodir)/sync
toolexeclibgosync_DATA = \
sync/atomic.gox
@@ -814,6 +856,7 @@ runtime_files = \
runtime/go-panic.c \
runtime/go-panic-defer.c \
runtime/go-print.c \
+ runtime/go-rand.c \
runtime/go-rec-big.c \
runtime/go-rec-nb-big.c \
runtime/go-rec-nb-small.c \
@@ -914,6 +957,10 @@ go_cmath_files = \
go_crypto_files = \
go/crypto/crypto.go
+go_csv_files = \
+ go/csv/reader.go \
+ go/csv/writer.go
+
go_ebnf_files = \
go/ebnf/ebnf.go \
go/ebnf/parser.go
@@ -947,9 +994,11 @@ go_hash_files = \
go/hash/hash.go
go_html_files = \
+ go/html/const.go \
go/html/doc.go \
go/html/entity.go \
go/html/escape.go \
+ go/html/node.go \
go/html/parse.go \
go/html/token.go
@@ -966,10 +1015,10 @@ go_http_files = \
go/http/response.go \
go/http/reverseproxy.go \
go/http/server.go \
+ go/http/sniff.go \
go/http/status.go \
go/http/transfer.go \
- go/http/transport.go \
- go/http/url.go
+ go/http/transport.go
go_image_files = \
go/image/color.go \
@@ -1041,6 +1090,9 @@ go_math_files = \
go/math/tanh.go \
go/math/unsafe.go
+go_mail_files = \
+ go/mail/message.go
+
go_mime_files = \
go/mime/grammar.go \
go/mime/mediatype.go \
@@ -1062,11 +1114,16 @@ go_mime_files = \
@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sock_file = go/net/sock_linux.go
@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sock_file = go/net/sock_linux.go
@LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
+@LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_stub.go
+@LIBGO_IS_LINUX_TRUE@go_net_sendfile_file = go/net/sendfile_linux.go
+@LIBGO_IS_LINUX_FALSE@go_net_interface_file = go/net/interface_stub.go
+@LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
go_net_files = \
go/net/cgo_unix.go \
$(go_net_cgo_file) \
go/net/dial.go \
go/net/dnsclient.go \
+ go/net/dnsclient_unix.go \
go/net/dnsconfig.go \
go/net/dnsmsg.go \
$(go_net_newpollserver_file) \
@@ -1074,19 +1131,27 @@ go_net_files = \
$(go_net_fd_os_file) \
go/net/file.go \
go/net/hosts.go \
+ go/net/interface.go \
+ $(go_net_interface_file) \
go/net/ip.go \
go/net/iprawsock.go \
+ go/net/iprawsock_posix.go \
go/net/ipsock.go \
- go/net/lookup.go \
+ go/net/ipsock_posix.go \
+ go/net/lookup_unix.go \
go/net/net.go \
go/net/parse.go \
go/net/pipe.go \
go/net/port.go \
+ $(go_net_sendfile_file) \
go/net/sock.go \
$(go_net_sock_file) \
go/net/tcpsock.go \
+ go/net/tcpsock_posix.go \
go/net/udpsock.go \
- go/net/unixsock.go
+ go/net/udpsock_posix.go \
+ go/net/unixsock.go \
+ go/net/unixsock_posix.go
go_netchan_files = \
go/netchan/common.go \
@@ -1118,11 +1183,14 @@ go_os_files = \
go/os/file_unix.go \
go/os/getwd.go \
go/os/path.go \
+ go/os/path_unix.go \
go/os/proc.go \
go/os/stat.go \
+ go/os/str.go \
$(go_os_sys_file) \
go/os/time.go \
- go/os/types.go
+ go/os/types.go \
+ signal_unix.go
go_patch_files = \
go/patch/apply.go \
@@ -1209,8 +1277,12 @@ go_tabwriter_files = \
go/tabwriter/tabwriter.go
go_template_files = \
- go/template/format.go \
- go/template/template.go
+ go/template/doc.go \
+ go/template/exec.go \
+ go/template/funcs.go \
+ go/template/helper.go \
+ go/template/parse.go \
+ go/template/set.go
go_testing_files = \
go/testing/benchmark.go \
@@ -1220,8 +1292,10 @@ go_time_files = \
go/time/format.go \
go/time/sleep.go \
go/time/sys.go \
+ go/time/sys_posix.go \
go/time/tick.go \
go/time/time.go \
+ go/time/zoneinfo_posix.go \
go/time/zoneinfo_unix.go
go_try_files = \
@@ -1230,9 +1304,13 @@ go_try_files = \
go_unicode_files = \
go/unicode/casetables.go \
go/unicode/digit.go \
+ go/unicode/graphic.go \
go/unicode/letter.go \
go/unicode/tables.go
+go_url_files = \
+ go/url/url.go
+
go_utf16_files = \
go/utf16/utf16.go
@@ -1246,6 +1324,7 @@ go_websocket_files = \
go/websocket/websocket.go
go_xml_files = \
+ go/xml/marshal.go \
go/xml/read.go \
go/xml/xml.go
@@ -1256,7 +1335,8 @@ go_archive_tar_files = \
go_archive_zip_files = \
go/archive/zip/reader.go \
- go/archive/zip/struct.go
+ go/archive/zip/struct.go \
+ go/archive/zip/writer.go
go_compress_bzip2_files = \
go/compress/bzip2/bit_reader.go \
@@ -1358,7 +1438,8 @@ go_crypto_openpgp_files = \
go_crypto_rand_files = \
go/crypto/rand/rand.go \
- go/crypto/rand/rand_unix.go
+ go/crypto/rand/rand_unix.go \
+ go/crypto/rand/util.go
go_crypto_rc4_files = \
go/crypto/rc4/rc4.go
@@ -1414,6 +1495,9 @@ go_crypto_openpgp_armor_files = \
go/crypto/openpgp/armor/armor.go \
go/crypto/openpgp/armor/encode.go
+go_crypto_openpgp_elgamal_files = \
+ go/crypto/openpgp/elgamal/elgamal.go
+
go_crypto_openpgp_error_files = \
go/crypto/openpgp/error/error.go
@@ -1434,6 +1518,9 @@ go_crypto_openpgp_packet_files = \
go_crypto_openpgp_s2k_files = \
go/crypto/openpgp/s2k/s2k.go
+go_crypto_x509_pkix_files = \
+ go/crypto/x509/pkix/pkix.go
+
go_debug_dwarf_files = \
go/debug/dwarf/buf.go \
go/debug/dwarf/const.go \
@@ -1458,11 +1545,6 @@ 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
@@ -1481,9 +1563,6 @@ go_encoding_git85_files = \
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
@@ -1491,23 +1570,35 @@ 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_exp_gui_files = \
+ go/exp/gui/gui.go
+
+go_exp_norm_files = \
+ go/exp/norm/composition.go \
+ go/exp/norm/forminfo.go \
+ go/exp/norm/normalize.go \
+ go/exp/norm/tables.go \
+ go/exp/norm/trie.go
+
+go_exp_regexp_files = \
+ go/exp/regexp/exec.go \
+ go/exp/regexp/regexp.go
+
+go_exp_gui_x11_files = \
+ go/exp/gui/x11/auth.go \
+ go/exp/gui/x11/conn.go
+
+go_exp_template_html_files = \
+ go/exp/template/html/context.go \
+ go/exp/template/html/escape.go
+
+go_exp_regexp_syntax_files = \
+ go/exp/regexp/syntax/compile.go \
+ go/exp/regexp/syntax/parse.go \
+ go/exp/regexp/syntax/perl_groups.go \
+ go/exp/regexp/syntax/prog.go \
+ go/exp/regexp/syntax/regexp.go \
+ go/exp/regexp/syntax/simplify.go
go_go_ast_files = \
go/go/ast/ast.go \
@@ -1517,6 +1608,12 @@ go_go_ast_files = \
go/go/ast/scope.go \
go/go/ast/walk.go
+go_go_build_files = \
+ go/go/build/build.go \
+ go/go/build/dir.go \
+ go/go/build/path.go \
+ syslist.go
+
go_go_doc_files = \
go/go/doc/comment.go \
go/go/doc/doc.go
@@ -1544,6 +1641,7 @@ go_go_typechecker_files = \
go/go/typechecker/universe.go
go_go_types_files = \
+ go/go/types/check.go \
go/go/types/const.go \
go/go/types/exportdata.go \
go/go/types/gcimporter.go \
@@ -1554,7 +1652,8 @@ go_hash_adler32_files = \
go/hash/adler32/adler32.go
go_hash_crc32_files = \
- go/hash/crc32/crc32.go
+ go/hash/crc32/crc32.go \
+ go/hash/crc32/crc32_generic.go
go_hash_crc64_files = \
go/hash/crc64/crc64.go
@@ -1578,7 +1677,15 @@ go_http_pprof_files = \
go/http/pprof/pprof.go
go_http_spdy_files = \
- go/http/spdy/protocol.go
+ go/http/spdy/read.go \
+ go/http/spdy/types.go \
+ go/http/spdy/write.go
+
+go_image_bmp_files = \
+ go/image/bmp/reader.go
+
+go_image_draw_files = \
+ go/image/draw/draw.go
go_image_gif_files = \
go/image/gif/reader.go
@@ -1612,7 +1719,8 @@ go_io_ioutil_files = \
go_mime_multipart_files = \
go/mime/multipart/formdata.go \
- go/mime/multipart/multipart.go
+ go/mime/multipart/multipart.go \
+ go/mime/multipart/writer.go
go_net_dict_files = \
go/net/dict/dict.go
@@ -1624,6 +1732,12 @@ go_net_textproto_files = \
go/net/textproto/textproto.go \
go/net/textproto/writer.go
+go_old_template_files = \
+ go/old/template/doc.go \
+ go/old/template/execute.go \
+ go/old/template/format.go \
+ go/old/template/parse.go
+
go_os_inotify_files = \
go/os/inotify/inotify_linux.go
@@ -1632,8 +1746,7 @@ go_os_user_files = \
go/os/user/lookup_unix.go
go_os_signal_files = \
- go/os/signal/signal.go \
- unix.go
+ go/os/signal/signal.go
go_path_filepath_files = \
go/path/filepath/match.go \
@@ -1650,6 +1763,12 @@ go_runtime_debug_files = \
go_runtime_pprof_files = \
go/runtime/pprof/pprof.go
+go_template_parse_files = \
+ go/template/parse/lex.go \
+ go/template/parse/node.go \
+ go/template/parse/parse.go \
+ go/template/parse/set.go
+
go_sync_atomic_files = \
go/sync/atomic/doc.go
@@ -1729,6 +1848,10 @@ go_testing_script_files = \
# 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
+@LIBGO_IS_LINUX_FALSE@syscall_netlink_file =
+
+# Support for netlink sockets and messages.
+@LIBGO_IS_LINUX_TRUE@syscall_netlink_file = syscalls/netlink_linux.go
go_syscall_files = \
$(syscall_errstr_file) \
$(syscall_errstr_decl_file) \
@@ -1736,6 +1859,7 @@ go_syscall_files = \
$(syscall_exec_os_file) \
$(syscall_wait_file) \
$(syscall_filesize_file) \
+ $(syscall_netlink_file) \
$(syscall_stat_file) \
$(syscall_sleep_file) \
syscalls/socket.go \
@@ -1766,6 +1890,7 @@ libgo_go_objs = \
bytes/index.lo \
cmath/cmath.lo \
crypto/crypto.lo \
+ csv/csv.lo \
ebnf/ebnf.lo \
exec/exec.lo \
expvar/expvar.lo \
@@ -1780,6 +1905,7 @@ libgo_go_objs = \
json/json.lo \
log/log.lo \
math/math.lo \
+ mail/mail.lo \
mime/mime.lo \
net/net.lo \
netchan/netchan.lo \
@@ -1804,6 +1930,7 @@ libgo_go_objs = \
time/time.lo \
try/try.lo \
unicode/unicode.lo \
+ url/url.lo \
utf16/utf16.lo \
utf8/utf8.lo \
websocket/websocket.lo \
@@ -1845,27 +1972,32 @@ libgo_go_objs = \
crypto/x509.lo \
crypto/xtea.lo \
crypto/openpgp/armor.lo \
+ crypto/openpgp/elgamal.lo \
crypto/openpgp/error.lo \
crypto/openpgp/packet.lo \
crypto/openpgp/s2k.lo \
+ crypto/x509/pkix.lo \
debug/dwarf.lo \
debug/elf.lo \
debug/gosym.lo \
debug/macho.lo \
debug/pe.lo \
- 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 \
+ exp/gui.lo \
+ exp/norm.lo \
+ exp/regexp.lo \
+ exp/gui/x11.lo \
+ exp/regexp/syntax.lo \
+ exp/template/html.lo \
go/ast.lo \
+ go/build.lo \
go/doc.lo \
go/parser.lo \
go/printer.lo \
@@ -1882,6 +2014,8 @@ libgo_go_objs = \
http/httptest.lo \
http/pprof.lo \
http/spdy.lo \
+ image/bmp.lo \
+ image/draw.lo \
image/gif.lo \
image/jpeg.lo \
image/png.lo \
@@ -1892,6 +2026,7 @@ libgo_go_objs = \
mime/multipart.lo \
net/dict.lo \
net/textproto.lo \
+ old/template.lo \
$(os_lib_inotify_lo) \
os/user.lo \
os/signal.lo \
@@ -1903,6 +2038,7 @@ libgo_go_objs = \
sync/atomic_c.lo \
syscalls/syscall.lo \
syscalls/errno.lo \
+ template/parse.lo \
testing/testing.lo \
testing/iotest.lo \
testing/quick.lo \
@@ -1967,19 +2103,6 @@ CHECK = \
fi
-# Check a package that is only tested if GCCGO_RUN_ALL_TESTS is set.
-CHECK_ON_REQUEST = \
- if test "$$GCCGO_RUN_ALL_TESTS" != ""; then \
- $(CHECK); \
- else \
- rm -f $@-testsum $@-testlog; \
- echo "Set GCCGO_RUN_ALL_TESTS in environment to run $(@D) test" > $@-testlog; \
- echo "UNTESTED: $(@D)" >> $@-testlog; \
- echo "UNTESTED: $(@D)"; \
- echo "UNTESTED: $(@D)" > $@-testsum; \
- fi
-
-
# Build all packages before checking any.
CHECK_DEPS = libgo.la libgobegin.a \
$(toolexeclibgo_DATA) \
@@ -2022,6 +2145,7 @@ TEST_PACKAGES = \
bufio/check \
bytes/check \
cmath/check \
+ csv/check \
ebnf/check \
exec/check \
expvar/check \
@@ -2030,10 +2154,12 @@ TEST_PACKAGES = \
gob/check \
html/check \
http/check \
+ image/check \
io/check \
json/check \
log/check \
math/check \
+ mail/check \
mime/check \
net/check \
netchan/check \
@@ -2057,6 +2183,7 @@ TEST_PACKAGES = \
time/check \
try/check \
unicode/check \
+ url/check \
utf16/check \
utf8/check \
websocket/check \
@@ -2098,6 +2225,7 @@ TEST_PACKAGES = \
crypto/x509/check \
crypto/xtea/check \
crypto/openpgp/armor/check \
+ crypto/openpgp/elgamal/check \
crypto/openpgp/packet/check \
crypto/openpgp/s2k/check \
debug/dwarf/check \
@@ -2110,12 +2238,14 @@ TEST_PACKAGES = \
encoding/binary/check \
encoding/git85/check \
encoding/hex/check \
- encoding/line/check \
encoding/pem/check \
exp/datafmt/check \
- exp/draw/check \
- exp/eval/check \
+ exp/norm/check \
+ exp/regexp/check \
+ exp/regexp/syntax/check \
+ exp/template/html/check \
go/ast/check \
+ $(go_build_check_omitted_since_it_calls_6g) \
go/parser/check \
go/printer/check \
go/scanner/check \
@@ -2129,6 +2259,7 @@ TEST_PACKAGES = \
http/cgi/check \
http/fcgi/check \
http/spdy/check \
+ image/draw/check \
image/jpeg/check \
image/png/check \
image/tiff/check \
@@ -2137,12 +2268,14 @@ TEST_PACKAGES = \
io/ioutil/check \
mime/multipart/check \
net/textproto/check \
+ old/template/check \
$(os_inotify_check) \
os/user/check \
os/signal/check \
path/filepath/check \
rpc/jsonrpc/check \
sync/atomic/check \
+ template/parse/check \
testing/quick/check \
testing/script/check
@@ -2324,6 +2457,7 @@ distclean-compile:
@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-rand.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@
@@ -2704,6 +2838,13 @@ go-print.lo: runtime/go-print.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-print.lo `test -f 'runtime/go-print.c' || echo '$(srcdir)/'`runtime/go-print.c
+go-rand.lo: runtime/go-rand.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-rand.lo -MD -MP -MF $(DEPDIR)/go-rand.Tpo -c -o go-rand.lo `test -f 'runtime/go-rand.c' || echo '$(srcdir)/'`runtime/go-rand.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-rand.Tpo $(DEPDIR)/go-rand.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-rand.c' object='go-rand.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-rand.lo `test -f 'runtime/go-rand.c' || echo '$(srcdir)/'`runtime/go-rand.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
@@ -3206,6 +3347,26 @@ uninstall-toolexeclibgocryptoopenpgpDATA:
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" && rm -f $$files
+install-toolexeclibgocryptox509DATA: $(toolexeclibgocryptox509_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgocryptox509dir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgocryptox509dir)"
+ @list='$(toolexeclibgocryptox509_DATA)'; test -n "$(toolexeclibgocryptox509dir)" || 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)$(toolexeclibgocryptox509dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgocryptox509dir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgocryptox509DATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgocryptox509_DATA)'; test -n "$(toolexeclibgocryptox509dir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgocryptox509dir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgocryptox509dir)" && rm -f $$files
install-toolexeclibgodebugDATA: $(toolexeclibgodebug_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgodebugdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgodebugdir)"
@@ -3266,6 +3427,66 @@ uninstall-toolexeclibgoexpDATA:
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgoexpdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgoexpdir)" && rm -f $$files
+install-toolexeclibgoexpguiDATA: $(toolexeclibgoexpgui_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoexpguidir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexpguidir)"
+ @list='$(toolexeclibgoexpgui_DATA)'; test -n "$(toolexeclibgoexpguidir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexpguidir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexpguidir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoexpguiDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoexpgui_DATA)'; test -n "$(toolexeclibgoexpguidir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoexpguidir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoexpguidir)" && rm -f $$files
+install-toolexeclibgoexpregexpDATA: $(toolexeclibgoexpregexp_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoexpregexpdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexpregexpdir)"
+ @list='$(toolexeclibgoexpregexp_DATA)'; test -n "$(toolexeclibgoexpregexpdir)" || 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)$(toolexeclibgoexpregexpdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexpregexpdir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoexpregexpDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoexpregexp_DATA)'; test -n "$(toolexeclibgoexpregexpdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoexpregexpdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoexpregexpdir)" && rm -f $$files
+install-toolexeclibgoexptemplateDATA: $(toolexeclibgoexptemplate_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoexptemplatedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexptemplatedir)"
+ @list='$(toolexeclibgoexptemplate_DATA)'; test -n "$(toolexeclibgoexptemplatedir)" || 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)$(toolexeclibgoexptemplatedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexptemplatedir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgoexptemplateDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoexptemplate_DATA)'; test -n "$(toolexeclibgoexptemplatedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoexptemplatedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoexptemplatedir)" && rm -f $$files
install-toolexeclibgogoDATA: $(toolexeclibgogo_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgogodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgogodir)"
@@ -3426,6 +3647,26 @@ uninstall-toolexeclibgonetDATA:
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgonetdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgonetdir)" && rm -f $$files
+install-toolexeclibgooldDATA: $(toolexeclibgoold_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgoolddir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoolddir)"
+ @list='$(toolexeclibgoold_DATA)'; test -n "$(toolexeclibgoolddir)" || 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)$(toolexeclibgoolddir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoolddir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgooldDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgoold_DATA)'; test -n "$(toolexeclibgoolddir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgoolddir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgoolddir)" && rm -f $$files
install-toolexeclibgoosDATA: $(toolexeclibgoos_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgoosdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoosdir)"
@@ -3526,6 +3767,26 @@ uninstall-toolexeclibgosyncDATA:
test -n "$$files" || exit 0; \
echo " ( cd '$(DESTDIR)$(toolexeclibgosyncdir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(toolexeclibgosyncdir)" && rm -f $$files
+install-toolexeclibgotemplateDATA: $(toolexeclibgotemplate_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(toolexeclibgotemplatedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgotemplatedir)"
+ @list='$(toolexeclibgotemplate_DATA)'; test -n "$(toolexeclibgotemplatedir)" || 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)$(toolexeclibgotemplatedir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgotemplatedir)" || exit $$?; \
+ done
+
+uninstall-toolexeclibgotemplateDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(toolexeclibgotemplate_DATA)'; test -n "$(toolexeclibgotemplatedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(toolexeclibgotemplatedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(toolexeclibgotemplatedir)" && rm -f $$files
install-toolexeclibgotestingDATA: $(toolexeclibgotesting_DATA)
@$(NORMAL_INSTALL)
test -z "$(toolexeclibgotestingdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgotestingdir)"
@@ -3863,7 +4124,7 @@ all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \
config.h
installdirs: installdirs-recursive
installdirs-am:
- for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohttpdir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgorpcdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)"; do \
+ for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgoexpguidir)" "$(DESTDIR)$(toolexeclibgoexpregexpdir)" "$(DESTDIR)$(toolexeclibgoexptemplatedir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohttpdir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgorpcdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotemplatedir)" "$(DESTDIR)$(toolexeclibgotestingdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-recursive
@@ -3930,15 +4191,21 @@ install-exec-am: install-multi install-toolexeclibLIBRARIES \
install-toolexeclibgocontainerDATA \
install-toolexeclibgocryptoDATA \
install-toolexeclibgocryptoopenpgpDATA \
+ install-toolexeclibgocryptox509DATA \
install-toolexeclibgodebugDATA \
install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
+ install-toolexeclibgoexpguiDATA \
+ install-toolexeclibgoexpregexpDATA \
+ install-toolexeclibgoexptemplateDATA \
install-toolexeclibgogoDATA install-toolexeclibgohashDATA \
install-toolexeclibgohttpDATA install-toolexeclibgoimageDATA \
install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \
- install-toolexeclibgoosDATA install-toolexeclibgopathDATA \
- install-toolexeclibgorpcDATA install-toolexeclibgoruntimeDATA \
- install-toolexeclibgosyncDATA install-toolexeclibgotestingDATA
+ install-toolexeclibgooldDATA install-toolexeclibgoosDATA \
+ install-toolexeclibgopathDATA install-toolexeclibgorpcDATA \
+ install-toolexeclibgoruntimeDATA install-toolexeclibgosyncDATA \
+ install-toolexeclibgotemplateDATA \
+ install-toolexeclibgotestingDATA
install-html: install-html-recursive
@@ -3987,18 +4254,23 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
uninstall-toolexeclibgocontainerDATA \
uninstall-toolexeclibgocryptoDATA \
uninstall-toolexeclibgocryptoopenpgpDATA \
+ uninstall-toolexeclibgocryptox509DATA \
uninstall-toolexeclibgodebugDATA \
uninstall-toolexeclibgoencodingDATA \
- uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \
- uninstall-toolexeclibgohashDATA \
+ uninstall-toolexeclibgoexpDATA \
+ uninstall-toolexeclibgoexpguiDATA \
+ uninstall-toolexeclibgoexpregexpDATA \
+ uninstall-toolexeclibgoexptemplateDATA \
+ uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgohttpDATA \
uninstall-toolexeclibgoimageDATA \
uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
uninstall-toolexeclibgomimeDATA uninstall-toolexeclibgonetDATA \
- uninstall-toolexeclibgoosDATA uninstall-toolexeclibgopathDATA \
- uninstall-toolexeclibgorpcDATA \
+ uninstall-toolexeclibgooldDATA uninstall-toolexeclibgoosDATA \
+ uninstall-toolexeclibgopathDATA uninstall-toolexeclibgorpcDATA \
uninstall-toolexeclibgoruntimeDATA \
uninstall-toolexeclibgosyncDATA \
+ uninstall-toolexeclibgotemplateDATA \
uninstall-toolexeclibgotestingDATA
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all all-multi \
@@ -4026,39 +4298,50 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
install-toolexeclibgocontainerDATA \
install-toolexeclibgocryptoDATA \
install-toolexeclibgocryptoopenpgpDATA \
+ install-toolexeclibgocryptox509DATA \
install-toolexeclibgodebugDATA \
install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \
+ install-toolexeclibgoexpguiDATA \
+ install-toolexeclibgoexpregexpDATA \
+ install-toolexeclibgoexptemplateDATA \
install-toolexeclibgogoDATA install-toolexeclibgohashDATA \
install-toolexeclibgohttpDATA install-toolexeclibgoimageDATA \
install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \
- install-toolexeclibgoosDATA install-toolexeclibgopathDATA \
- install-toolexeclibgorpcDATA install-toolexeclibgoruntimeDATA \
- install-toolexeclibgosyncDATA 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 \
+ install-toolexeclibgooldDATA install-toolexeclibgoosDATA \
+ install-toolexeclibgopathDATA install-toolexeclibgorpcDATA \
+ install-toolexeclibgoruntimeDATA install-toolexeclibgosyncDATA \
+ install-toolexeclibgotemplateDATA \
+ 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-toolexeclibgocryptox509DATA \
uninstall-toolexeclibgodebugDATA \
uninstall-toolexeclibgoencodingDATA \
- uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \
- uninstall-toolexeclibgohashDATA \
+ uninstall-toolexeclibgoexpDATA \
+ uninstall-toolexeclibgoexpguiDATA \
+ uninstall-toolexeclibgoexpregexpDATA \
+ uninstall-toolexeclibgoexptemplateDATA \
+ uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \
uninstall-toolexeclibgohttpDATA \
uninstall-toolexeclibgoimageDATA \
uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
uninstall-toolexeclibgomimeDATA uninstall-toolexeclibgonetDATA \
- uninstall-toolexeclibgoosDATA uninstall-toolexeclibgopathDATA \
- uninstall-toolexeclibgorpcDATA \
+ uninstall-toolexeclibgooldDATA uninstall-toolexeclibgoosDATA \
+ uninstall-toolexeclibgopathDATA uninstall-toolexeclibgorpcDATA \
uninstall-toolexeclibgoruntimeDATA \
uninstall-toolexeclibgosyncDATA \
+ uninstall-toolexeclibgotemplateDATA \
uninstall-toolexeclibgotestingDATA
@@ -4108,14 +4391,15 @@ s-syscall_arch: Makefile
$(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
+asn1/asn1.lo: $(go_asn1_files) big.gox 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 os.gox
+big/big.lo: $(go_big_files) encoding/binary.gox fmt.gox io.gox os.gox \
+ rand.gox strings.gox
$(BUILDPACKAGE)
big/check: $(CHECK_DEPS)
@$(CHECK)
@@ -4147,6 +4431,13 @@ crypto/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/check
+csv/csv.lo: $(go_csv_files) bufio.gox bytes.gox fmt.gox io.gox os.gox \
+ strings.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+csv/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: csv/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)
@@ -4154,7 +4445,8 @@ ebnf/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: ebnf/check
-exec/exec.lo: $(go_exec_files) os.gox strconv.gox strings.gox
+exec/exec.lo: $(go_exec_files) bytes.gox io.gox os.gox strconv.gox \
+ strings.gox syscall.gox
$(BUILDPACKAGE)
exec/check: $(CHECK_DEPS)
@$(CHECK)
@@ -4202,11 +4494,11 @@ html/check: $(CHECK_DEPS)
.PHONY: html/check
http/http.lo: $(go_http_files) bufio.gox bytes.gox compress/gzip.gox \
- container/vector.gox crypto/rand.gox crypto/tls.gox \
- encoding/base64.gox fmt.gox io.gox io/ioutil.gox log.gox \
+ crypto/rand.gox crypto/tls.gox encoding/base64.gox \
+ encoding/binary.gox fmt.gox io.gox io/ioutil.gox log.gox \
mime.gox mime/multipart.gox net.gox net/textproto.gox os.gox \
- path.gox path/filepath.gox sort.gox strconv.gox strings.gox \
- sync.gox time.gox utf8.gox
+ path.gox path/filepath.gox runtime/debug.gox sort.gox \
+ strconv.gox strings.gox sync.gox time.gox url.gox utf8.gox
$(BUILDPACKAGE)
http/check: $(CHECK_DEPS)
@$(CHECK)
@@ -4224,10 +4516,9 @@ io/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: io/check
-json/json.lo: $(go_json_files) bytes.gox container/vector.gox \
- encoding/base64.gox fmt.gox io.gox math.gox os.gox \
- reflect.gox runtime.gox strconv.gox strings.gox unicode.gox \
- utf16.gox utf8.gox
+json/json.lo: $(go_json_files) bytes.gox encoding/base64.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)
@@ -4246,6 +4537,14 @@ math/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: math/check
+mail/mail.lo: $(go_mail_files) bufio.gox bytes.gox encoding/base64.gox \
+ fmt.gox io.gox io/ioutil.gox log.gox net/textproto.gox os.gox \
+ strconv.gox strings.gox time.gox
+ $(BUILDPACKAGE)
+mail/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: mail/check
+
mime/mime.lo: $(go_mime_files) bufio.gox bytes.gox fmt.gox os.gox strings.gox \
sync.gox unicode.gox
$(BUILDPACKAGE)
@@ -4258,7 +4557,7 @@ net/net.lo: $(go_net_files) bytes.gox fmt.gox io.gox os.gox rand.gox \
syscall.gox time.gox
$(BUILDPACKAGE)
net/check: $(CHECK_DEPS)
- @$(CHECK_ON_REQUEST)
+ @$(CHECK)
.PHONY: net/check
netchan/netchan.lo: $(go_netchan_files) gob.gox io.gox log.gox net.gox os.gox \
@@ -4274,6 +4573,10 @@ os/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: os/check
+signal_unix.go: $(srcdir)/go/os/mkunixsignals.sh sysinfo.go
+ $(SHELL) $(srcdir)/go/os/mkunixsignals.sh sysinfo.go > $@.tmp
+ mv -f $@.tmp $@
+
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
@@ -4336,7 +4639,7 @@ smtp/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: smtp/check
-sort/sort.lo: $(go_sort_files)
+sort/sort.lo: $(go_sort_files) math.gox
$(BUILDPACKAGE)
sort/check: $(CHECK_DEPS)
@$(CHECK)
@@ -4366,7 +4669,7 @@ syslog/syslog.lo: $(go_syslog_files) fmt.gox log.gox net.gox os.gox syscall.gox
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_ON_REQUEST)
+ @$(CHECK)
.PHONY: syslog/check
tabwriter/tabwriter.lo: $(go_tabwriter_files) bytes.gox io.gox os.gox utf8.gox
@@ -4375,15 +4678,17 @@ 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
+template/template.lo: $(go_template_files) bytes.gox fmt.gox io.gox \
+ io/ioutil.gox os.gox path/filepath.gox reflect.gox \
+ runtime.gox strings.gox template/parse.gox unicode.gox \
+ url.gox utf8.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 runtime/pprof.gox time.gox
+ runtime.gox runtime/pprof.gox strings.gox strconv.gox time.gox
$(BUILDPACKAGE)
testing/check: $(CHECK_DEPS)
@$(CHECK)
@@ -4408,6 +4713,12 @@ unicode/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: unicode/check
+url/url.lo: $(go_url_files) os.gox strconv.gox strings.gox
+ $(BUILDPACKAGE)
+url/check: $(CHECK_DEPS)
+ @$(CHECK)
+.PHONY: url/check
+
utf16/utf16.lo: $(go_utf16_files) unicode.gox
$(BUILDPACKAGE)
utf16/check: $(CHECK_DEPS)
@@ -4421,9 +4732,8 @@ utf8/check: $(CHECK_DEPS)
.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
+ crypto/md5.gox crypto/tls.gox encoding/binary.gox fmt.gox \
+ http.gox io.gox net.gox os.gox rand.gox strings.gox url.gox
$(BUILDPACKAGE)
websocket/check: $(CHECK_DEPS)
@$(CHECK)
@@ -4444,9 +4754,9 @@ archive/tar/check: $(CHECK_DEPS)
@$(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 io/ioutil.gox os.gox
+archive/zip.lo: $(go_archive_zip_files) bufio.gox compress/flate.gox \
+ encoding/binary.gox hash.gox hash/crc32.gox \
+ encoding/binary.gox io.gox io/ioutil.gox os.gox time.gox
$(BUILDPACKAGE)
archive/zip/check: $(CHECK_DEPS)
@$(MKDIR_P) archive/zip
@@ -4599,25 +4909,27 @@ crypto/md5/check: $(CHECK_DEPS)
.PHONY: crypto/md5/check
crypto/ocsp.lo: $(go_crypto_ocsp_files) asn1.gox crypto.gox crypto/rsa.gox \
- crypto/sha1.gox crypto/x509.gox os.gox time.gox
+ crypto/sha1.gox crypto/x509.gox crypto/x509/pkix.gox os.gox \
+ time.gox
$(BUILDPACKAGE)
crypto/ocsp/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/ocsp
@$(CHECK)
.PHONY: crypto/ocsp/check
-crypto/openpgp.lo: $(go_crypto_openpgp_files) crypto.gox crypto/dsa.gox \
+crypto/openpgp.lo: $(go_crypto_openpgp_files) crypto.gox \
crypto/openpgp/armor.gox crypto/openpgp/error.gox \
- crypto/openpgp/packet.gox crypto/rsa.gox crypto/sha256.gox \
- hash.gox io.gox os.gox strconv.gox time.gox
+ crypto/openpgp/packet.gox crypto/openpgp/s2k.gox \
+ crypto/rand.gox crypto/rsa.gox crypto/sha256.gox hash.gox \
+ io.gox os.gox strconv.gox time.gox
$(BUILDPACKAGE)
crypto/openpgp/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/openpgp
@$(CHECK)
.PHONY: crypto/openpgp/check
-crypto/rand.lo: $(go_crypto_rand_files) bufio.gox crypto/aes.gox io.gox \
- os.gox sync.gox time.gox
+crypto/rand.lo: $(go_crypto_rand_files) big.gox bufio.gox crypto/aes.gox \
+ io.gox os.gox sync.gox time.gox
$(BUILDPACKAGE)
crypto/rand/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/rand
@@ -4638,8 +4950,9 @@ crypto/ripemd160/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/ripemd160/check
-crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/sha1.gox \
- crypto/subtle.gox encoding/hex.gox hash.gox io.gox os.gox
+crypto/rsa.lo: $(go_crypto_rsa_files) big.gox crypto.gox crypto/rand.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
@@ -4678,9 +4991,9 @@ crypto/tls.lo: $(go_crypto_tls_files) big.gox bytes.gox crypto.gox \
crypto/aes.gox crypto/cipher.gox crypto/elliptic.gox \
crypto/hmac.gox crypto/md5.gox crypto/rand.gox crypto/rc4.gox \
crypto/rsa.gox crypto/sha1.gox crypto/subtle.gox \
- crypto/x509.gox encoding/pem.gox hash.gox io.gox \
- io/ioutil.gox net.gox os.gox strconv.gox strings.gox sync.gox \
- time.gox
+ crypto/x509.gox crypto/x509/pkix.gox encoding/pem.gox \
+ hash.gox io.gox io/ioutil.gox net.gox os.gox strconv.gox \
+ strings.gox sync.gox time.gox
$(BUILDPACKAGE)
crypto/tls/check: $(CHECK_DEPS)
@$(MKDIR_P) crypto/tls
@@ -4694,9 +5007,9 @@ crypto/twofish/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/twofish/check
-crypto/x509.lo: $(go_crypto_x509_files) asn1.gox big.gox bytes.gox \
- container/vector.gox crypto.gox crypto/rsa.gox \
- crypto/sha1.gox encoding/pem.gox hash.gox os.gox strings.gox \
+crypto/x509.lo: $(go_crypto_x509_files) asn1.gox big.gox bytes.gox crypto.gox \
+ crypto/dsa.gox crypto/rsa.gox crypto/sha1.gox \
+ crypto/x509/pkix.gox encoding/pem.gox os.gox strings.gox \
time.gox
$(BUILDPACKAGE)
crypto/x509/check: $(CHECK_DEPS)
@@ -4719,6 +5032,14 @@ crypto/openpgp/armor/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: crypto/openpgp/armor/check
+crypto/openpgp/elgamal.lo: $(go_crypto_openpgp_elgamal_files) big.gox \
+ crypto/rand.gox crypto/subtle.gox io.gox os.gox
+ $(BUILDPACKAGE)
+crypto/openpgp/elgamal/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/openpgp/elgamal
+ @$(CHECK)
+.PHONY: crypto/openpgp/elgamal/check
+
crypto/openpgp/error.lo: $(go_crypto_openpgp_error_files) strconv.gox
$(BUILDPACKAGE)
crypto/openpgp/error/check: $(CHECK_DEPS)
@@ -4729,9 +5050,10 @@ crypto/openpgp/error/check: $(CHECK_DEPS)
crypto/openpgp/packet.lo: $(go_crypto_openpgp_packet_files) big.gox bytes.gox \
compress/flate.gox compress/zlib.gox crypto.gox \
crypto/aes.gox crypto/cast5.gox crypto/cipher.gox \
- crypto/dsa.gox crypto/openpgp/error.gox \
- crypto/openpgp/s2k.gox crypto/rand.gox crypto/rsa.gox \
- crypto/sha1.gox crypto/subtle.gox encoding/binary.gox fmt.gox \
+ crypto/dsa.gox crypto/openpgp/elgamal.gox \
+ crypto/openpgp/error.gox crypto/openpgp/s2k.gox \
+ crypto/rand.gox crypto/rsa.gox crypto/sha1.gox \
+ crypto/subtle.gox encoding/binary.gox fmt.gox \
hash.gox io.gox io/ioutil.gox os.gox strconv.gox strings.gox
$(BUILDPACKAGE)
crypto/openpgp/packet/check: $(CHECK_DEPS)
@@ -4740,15 +5062,22 @@ crypto/openpgp/packet/check: $(CHECK_DEPS)
.PHONY: crypto/openpgp/packet/check
crypto/openpgp/s2k.lo: $(go_crypto_openpgp_s2k_files) crypto.gox \
- 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
+ crypto/md5.gox crypto/openpgp/error.gox crypto/rand.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
+crypto/x509/pkix.lo: $(go_crypto_x509_pkix_files) asn1.gox big.gox time.gox
+ $(BUILDPACKAGE)
+crypto/x509/pkix/check: $(CHECK_DEPS)
+ @$(MKDIR_P) crypto/x509/pkix
+ @$(CHECK)
+.PHONY: crypto/x509/pkix/check
+
debug/dwarf.lo: $(go_debug_dwarf_files) encoding/binary.gox os.gox strconv.gox
$(BUILDPACKAGE)
debug/dwarf/check: $(CHECK_DEPS)
@@ -4788,15 +5117,6 @@ debug/pe/check: $(CHECK_DEPS)
@$(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)
@@ -4834,20 +5154,13 @@ encoding/git85/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: encoding/git85/check
-encoding/hex.lo: $(go_encoding_hex_files) os.gox strconv.gox
+encoding/hex.lo: $(go_encoding_hex_files) bytes.gox io.gox 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)
@@ -4855,39 +5168,87 @@ encoding/pem/check: $(CHECK_DEPS)
@$(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
+exp/datafmt.lo: $(go_exp_datafmt_files) bytes.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 image/ycbcr.gox os.gox
+exp/gui.lo: $(go_exp_gui_files) image.gox image/draw.gox os.gox
+ $(BUILDPACKAGE)
+exp/gui/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/gui
+ @$(CHECK)
+.PHONY: exp/gui/check
+
+exp/norm.lo: $(go_exp_norm_files) utf8.gox
+ $(BUILDPACKAGE)
+exp/norm/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/norm
+ @$(CHECK)
+.PHONY: exp/norm/check
+
+exp/regexp.lo: $(go_exp_regexp_files) bytes.gox exp/regexp/syntax.gox io.gox \
+ os.gox strings.gox sync.gox utf8.gox
+ $(BUILDPACKAGE)
+exp/regexp/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/regexp
+ @$(CHECK)
+.PHONY: exp/regexp/check
+
+exp/gui/x11.lo: $(go_exp_gui_x11_files) bufio.gox exp/gui.gox image.gox \
+ image/draw.gox io.gox log.gox net.gox os.gox strconv.gox \
+ strings.gox time.gox
+ $(BUILDPACKAGE)
+exp/gui/x11/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/gui/x11
+ @$(CHECK)
+.PHONY: exp/gui/x11/check
+
+exp/regexp/syntax.lo: $(go_exp_regexp_syntax_files) bytes.gox os.gox sort.gox strconv.gox strings.gox unicode.gox utf8.gox
$(BUILDPACKAGE)
-exp/draw/check: $(CHECK_DEPS)
- @$(MKDIR_P) exp/draw
+exp/regexp/syntax/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/regexp/syntax
@$(CHECK)
-.PHONY: exp/draw/check
+.PHONY: exp/regexp/syntax/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
+exp/template/html.lo: $(go_exp_template_html_files) fmt.gox template.gox \
+ template/parse.gox
$(BUILDPACKAGE)
-exp/eval/check: $(CHECK_DEPS)
- @$(MKDIR_P) exp/eval
+exp/template/html/check: $(CHECK_DEPS)
+ @$(MKDIR_P) exp/template/html
@$(CHECK)
-.PHONY: exp/eval/check
+.PHONY: exp/template/html/check
go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/scanner.gox go/token.gox \
- io.gox os.gox reflect.gox unicode.gox utf8.gox
+ io.gox os.gox reflect.gox strconv.gox unicode.gox utf8.gox
$(BUILDPACKAGE)
go/ast/check: $(CHECK_DEPS)
@$(MKDIR_P) go/ast
@$(CHECK)
.PHONY: go/ast/check
+go/build.lo: $(go_go_build_files) bytes.gox exec.gox fmt.gox go/parser.gox \
+ go/token.gox log.gox os.gox path/filepath.gox regexp.gox \
+ runtime.gox strconv.gox strings.gox runtime.gox
+ $(BUILDPACKAGE)
+go/build/check: $(CHECK_DEPS)
+ @$(MKDIR_P) go/build
+ @$(CHECK)
+.PHONY: go/build/check
+
+syslist.go: s-syslist; @true
+s-syslist: Makefile
+ echo '// Generated automatically by make.' >syslist.go.tmp
+ echo 'package build' >>syslist.go.tmp
+ echo 'const goosList = "$(GOOS)"' >>syslist.go.tmp
+ echo 'const goarchList = "$(GOARCH)"' >>syslist.go.tmp
+ $(SHELL) $(srcdir)/../move-if-change syslist.go.tmp syslist.go
+ $(STAMP) $@
+
go/doc.lo: $(go_go_doc_files) go/ast.gox go/token.gox io.gox regexp.gox \
sort.gox strings.gox template.gox
$(BUILDPACKAGE)
@@ -4914,9 +5275,9 @@ go/printer/check: $(CHECK_DEPS)
@$(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/filepath.gox sort.gox \
- strconv.gox unicode.gox utf8.gox
+go/scanner.lo: $(go_go_scanner_files) bytes.gox fmt.gox go/token.gox io.gox \
+ os.gox path/filepath.gox sort.gox strconv.gox unicode.gox \
+ utf8.gox
$(BUILDPACKAGE)
go/scanner/check: $(CHECK_DEPS)
@$(MKDIR_P) go/scanner
@@ -4940,7 +5301,7 @@ go/typechecker/check: $(CHECK_DEPS)
go/types.lo: $(go_go_types_files) big.gox bufio.gox fmt.gox go/ast.gox \
go/token.gox io.gox os.gox path/filepath.gox runtime.gox \
- scanner.gox strconv.gox strings.gox
+ scanner.gox sort.gox strconv.gox strings.gox
$(BUILDPACKAGE)
go/types/check: $(CHECK_DEPS)
@$(MKDIR_P) go/types
@@ -4954,7 +5315,7 @@ hash/adler32/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: hash/adler32/check
-hash/crc32.lo: $(go_hash_crc32_files) hash.gox os.gox
+hash/crc32.lo: $(go_hash_crc32_files) hash.gox os.gox sync.gox
$(BUILDPACKAGE)
hash/crc32/check: $(CHECK_DEPS)
@$(MKDIR_P) hash/crc32
@@ -4975,10 +5336,9 @@ hash/fnv/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: hash/fnv/check
-http/cgi.lo: $(go_http_cgi_files) bufio.gox bytes.gox crypto/tls.gox \
- exec.gox fmt.gox http.gox net.gox io.gox io/ioutil.gox \
- log.gox os.gox path/filepath.gox regexp.gox strconv.gox \
- strings.gox
+http/cgi.lo: $(go_http_cgi_files) bufio.gox crypto/tls.gox exec.gox fmt.gox \
+ http.gox net.gox io.gox io/ioutil.gox log.gox os.gox \
+ path/filepath.gox regexp.gox strconv.gox strings.gox url.gox
$(BUILDPACKAGE)
http/cgi/check: $(CHECK_DEPS)
@$(MKDIR_P) http/cgi
@@ -4995,7 +5355,8 @@ http/fcgi/check: $(CHECK_DEPS)
.PHONY: http/fcgi/check
http/httptest.lo: $(go_http_httptest_files) bytes.gox crypto/rand.gox \
- crypto/tls.gox fmt.gox http.gox net.gox os.gox time.gox
+ crypto/tls.gox flag.gox fmt.gox http.gox net.gox os.gox \
+ time.gox
$(BUILDPACKAGE)
http/httptest/check: $(CHECK_DEPS)
@$(MKDIR_P) http/httptest
@@ -5019,6 +5380,20 @@ http/spdy/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: http/spdy/check
+image/bmp.lo: $(go_image_bmp_files) image.gox io.gox os.gox
+ $(BUILDPACKAGE)
+image/bmp/check: $(CHECK_DEPS)
+ @$(MKDIR_P) image/bmp
+ @$(CHECK)
+.PHONY: image/bmp/check
+
+image/draw.lo: $(go_image_draw_files) image.gox image/ycbcr.gox
+ $(BUILDPACKAGE)
+image/draw/check: $(CHECK_DEPS)
+ @$(MKDIR_P) image/draw
+ @$(CHECK)
+.PHONY: image/draw/check
+
image/gif.lo: $(go_image_gif_files) bufio.gox compress/lzw.gox fmt.gox \
image.gox io.gox os.gox
$(BUILDPACKAGE)
@@ -5074,28 +5449,36 @@ io/ioutil/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: io/ioutil/check
-mime/multipart.lo: $(go_mime_multipart_files) bufio.gox bytes.gox fmt.gox \
- io.gox io/ioutil.gox mime.gox net/textproto.gox os.gox \
- regexp.gox
+mime/multipart.lo: $(go_mime_multipart_files) bufio.gox bytes.gox \
+ crypto/rand.gox fmt.gox io.gox io/ioutil.gox mime.gox \
+ net/textproto.gox os.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
+net/dict.lo: $(go_net_dict_files) 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
+net/textproto.lo: $(go_net_textproto_files) bufio.gox bytes.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
+old/template.lo: $(go_old_template_files) bytes.gox fmt.gox io.gox \
+ io/ioutil.gox os.gox reflect.gox strconv.gox strings.gox \
+ unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+old/template/check: $(CHECK_DEPS)
+ @$(MKDIR_P) old/template
+ @$(CHECK)
+.PHONY: old/template/check
+
os/inotify.lo: $(go_os_inotify_files) fmt.gox os.gox strings.gox syscall.gox
$(BUILDPACKAGE)
os/inotify/check: $(CHECK_DEPS)
@@ -5111,19 +5494,15 @@ os/user/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: os/user/check
-os/signal.lo: $(go_os_signal_files) runtime.gox strconv.gox
+os/signal.lo: $(go_os_signal_files) os.gox runtime.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 $@
-
-path/filepath.lo: $(go_path_filepath_files) bytes.gox os.gox sort.gox \
- strings.gox utf8.gox
+path/filepath.lo: $(go_path_filepath_files) bytes.gox os.gox runtime.gox \
+ sort.gox strings.gox utf8.gox
$(BUILDPACKAGE)
path/filepath/check: $(CHECK_DEPS)
@$(MKDIR_P) path/filepath
@@ -5163,6 +5542,14 @@ sync/atomic/check: $(CHECK_DEPS)
@$(CHECK)
.PHONY: sync/atomic/check
+template/parse.lo: $(go_template_parse_files) bytes.gox fmt.gox os.gox \
+ runtime.gox strconv.gox strings.gox unicode.gox utf8.gox
+ $(BUILDPACKAGE)
+template/parse/check: $(CHECK_DEPS)
+ @$(MKDIR_P) template/parse
+ @$(CHECK)
+.PHONY: template/parse/check
+
testing/iotest.lo: $(go_testing_iotest_files) io.gox log.gox os.gox
$(BUILDPACKAGE)
testing/iotest/check: $(CHECK_DEPS)
@@ -5209,6 +5596,8 @@ cmath.gox: cmath/cmath.lo
$(BUILDGOX)
crypto.gox: crypto/crypto.lo
$(BUILDGOX)
+csv.gox: csv/csv.lo
+ $(BUILDGOX)
ebnf.gox: ebnf/ebnf.lo
$(BUILDGOX)
exec.gox: exec/exec.lo
@@ -5237,6 +5626,8 @@ log.gox: log/log.lo
$(BUILDGOX)
math.gox: math/math.lo
$(BUILDGOX)
+mail.gox: mail/mail.lo
+ $(BUILDGOX)
mime.gox: mime/mime.lo
$(BUILDGOX)
net.gox: net/net.lo
@@ -5287,6 +5678,8 @@ try.gox: try/try.lo
$(BUILDGOX)
unicode.gox: unicode/unicode.lo
$(BUILDGOX)
+url.gox: url/url.lo
+ $(BUILDGOX)
utf16.gox: utf16/utf16.lo
$(BUILDGOX)
utf8.gox: utf8/utf8.lo
@@ -5374,6 +5767,8 @@ crypto/xtea.gox: crypto/xtea.lo
crypto/openpgp/armor.gox: crypto/openpgp/armor.lo
$(BUILDGOX)
+crypto/openpgp/elgamal.gox: crypto/openpgp/elgamal.lo
+ $(BUILDGOX)
crypto/openpgp/error.gox: crypto/openpgp/error.lo
$(BUILDGOX)
crypto/openpgp/packet.gox: crypto/openpgp/packet.lo
@@ -5381,6 +5776,9 @@ crypto/openpgp/packet.gox: crypto/openpgp/packet.lo
crypto/openpgp/s2k.gox: crypto/openpgp/s2k.lo
$(BUILDGOX)
+crypto/x509/pkix.gox: crypto/x509/pkix.lo
+ $(BUILDGOX)
+
debug/dwarf.gox: debug/dwarf.lo
$(BUILDGOX)
debug/elf.gox: debug/elf.lo
@@ -5391,8 +5789,6 @@ 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)
@@ -5406,20 +5802,31 @@ 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
+exp/gui.gox: exp/gui.lo
$(BUILDGOX)
-exp/eval.gox: exp/eval.lo
+exp/norm.gox: exp/norm.lo
+ $(BUILDGOX)
+exp/regexp.gox: exp/regexp.lo
+ $(BUILDGOX)
+
+exp/gui/x11.gox: exp/gui/x11.lo
+ $(BUILDGOX)
+
+exp/regexp/syntax.gox: exp/regexp/syntax.lo
+ $(BUILDGOX)
+
+exp/template/html.gox: exp/template/html.lo
$(BUILDGOX)
go/ast.gox: go/ast.lo
$(BUILDGOX)
+go/build.gox: go/build.lo
+ $(BUILDGOX)
go/doc.gox: go/doc.lo
$(BUILDGOX)
go/parser.gox: go/parser.lo
@@ -5455,6 +5862,10 @@ http/pprof.gox: http/pprof.lo
http/spdy.gox: http/spdy.lo
$(BUILDGOX)
+image/bmp.gox: image/bmp.lo
+ $(BUILDGOX)
+image/draw.gox: image/draw.lo
+ $(BUILDGOX)
image/gif.gox: image/gif.lo
$(BUILDGOX)
image/jpeg.gox: image/jpeg.lo
@@ -5480,6 +5891,9 @@ net/dict.gox: net/dict.lo
net/textproto.gox: net/textproto.lo
$(BUILDGOX)
+old/template.gox: old/template.lo
+ $(BUILDGOX)
+
os/inotify.gox: os/inotify.lo
$(BUILDGOX)
os/user.gox: os/user.lo
@@ -5501,6 +5915,9 @@ runtime/pprof.gox: runtime/pprof.lo
sync/atomic.gox: sync/atomic.lo
$(BUILDGOX)
+template/parse.gox: template/parse.lo
+ $(BUILDGOX)
+
testing/iotest.gox: testing/iotest.lo
$(BUILDGOX)
testing/quick.gox: testing/quick.lo
diff --git a/libgo/config.h.in b/libgo/config.h.in
index d604392323a..be4a13a8b52 100644
--- a/libgo/config.h.in
+++ b/libgo/config.h.in
@@ -12,12 +12,24 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
+/* Define to 1 if you have the <linux/filter.h> header file. */
+#undef HAVE_LINUX_FILTER_H
+
+/* Define to 1 if you have the <linux/netlink.h> header file. */
+#undef HAVE_LINUX_NETLINK_H
+
+/* Define to 1 if you have the <linux/rtnetlink.h> header file. */
+#undef HAVE_LINUX_RTNETLINK_H
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mincore' function. */
#undef HAVE_MINCORE
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
/* Define to 1 if the system has the type `off64_t'. */
#undef HAVE_OFF64_T
@@ -71,6 +83,9 @@
/* Define to 1 if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
diff --git a/libgo/configure b/libgo/configure
index 032867f26dd..e6b5d15ba59 100755
--- a/libgo/configure
+++ b/libgo/configure
@@ -617,7 +617,6 @@ USING_SPLIT_STACK_FALSE
USING_SPLIT_STACK_TRUE
SPLIT_STACK
OSCFLAGS
-GO_DEBUG_PROC_REGS_OS_ARCH_FILE
GO_SYSCALLS_SYSCALL_OS_ARCH_FILE
GOARCH
LIBGO_IS_X86_64_FALSE
@@ -10914,7 +10913,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 10917 "configure"
+#line 10916 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11020,7 +11019,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11023 "configure"
+#line 11022 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -13558,12 +13557,6 @@ if test -f ${srcdir}/syscalls/syscall_${GOOS}_${GOARCH}.go; then
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
-
-
case "$target" in
mips-sgi-irix6.5*)
# IRIX 6 needs _XOPEN_SOURCE=500 for the XPG5 version of struct
@@ -14252,7 +14245,7 @@ no)
;;
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 sys/select.h
+for ac_header in sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.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"
@@ -14266,6 +14259,26 @@ fi
done
+
+for ac_header in linux/filter.h linux/netlink.h linux/rtnetlink.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" "#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+"
+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='#'
diff --git a/libgo/configure.ac b/libgo/configure.ac
index a11dc4db444..6702c26c2f8 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -255,12 +255,6 @@ if test -f ${srcdir}/syscalls/syscall_${GOOS}_${GOARCH}.go; then
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 Some targets need special flags to build sysinfo.go.
case "$target" in
mips-sgi-irix6.5*)
@@ -431,7 +425,14 @@ no)
;;
esac
-AC_CHECK_HEADERS(sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h)
+AC_CHECK_HEADERS(sys/mman.h syscall.h sys/epoll.h sys/ptrace.h sys/syscall.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/if.h)
+
+AC_CHECK_HEADERS([linux/filter.h linux/netlink.h linux/rtnetlink.h], [], [],
+[#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+
AM_CONDITIONAL(HAVE_SYS_MMAN_H, test "$ac_cv_header_sys_mman_h" = yes)
AC_CHECK_FUNCS(srandom random strerror_r strsignal wait4 mincore setenv)
diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go
index ad06b6dac54..45d95c3df29 100644
--- a/libgo/go/archive/tar/reader.go
+++ b/libgo/go/archive/tar/reader.go
@@ -16,7 +16,7 @@ import (
)
var (
- HeaderError os.Error = os.ErrorString("invalid tar header")
+ HeaderError = os.NewError("invalid tar header")
)
// A Reader provides sequential access to the contents of a tar archive.
diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go
index 32fc8f9151a..f473c900f26 100644
--- a/libgo/go/archive/tar/reader_test.go
+++ b/libgo/go/archive/tar/reader_test.go
@@ -178,7 +178,6 @@ func TestPartialRead(t *testing.T) {
}
}
-
func TestIncrementalRead(t *testing.T) {
test := gnuTarTest
f, err := os.Open(test.file)
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
index 17464c5d8e4..f92f9297ada 100644
--- a/libgo/go/archive/zip/reader.go
+++ b/libgo/go/archive/zip/reader.go
@@ -2,18 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/*
-Package zip 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"
@@ -24,9 +16,9 @@ import (
)
var (
- FormatError = os.NewError("not a valid zip file")
- UnsupportedMethod = os.NewError("unsupported compression algorithm")
- ChecksumError = os.NewError("checksum error")
+ FormatError = os.NewError("zip: not a valid zip file")
+ UnsupportedMethod = os.NewError("zip: unsupported compression algorithm")
+ ChecksumError = os.NewError("zip: checksum error")
)
type Reader struct {
@@ -44,15 +36,14 @@ type File struct {
FileHeader
zipr io.ReaderAt
zipsize int64
- headerOffset uint32
- bodyOffset int64
+ headerOffset int64
}
func (f *File) hasDataDescriptor() bool {
return f.Flags&0x8 != 0
}
-// OpenReader will open the Zip file specified by name and return a ReaderCloser.
+// OpenReader will open the Zip file specified by name and return a ReadCloser.
func OpenReader(name string) (*ReadCloser, os.Error) {
f, err := os.Open(name)
if err != nil {
@@ -87,18 +78,33 @@ func (z *Reader) init(r io.ReaderAt, size int64) os.Error {
return err
}
z.r = r
- z.File = make([]*File, end.directoryRecords)
+ z.File = make([]*File, 0, end.directoryRecords)
z.Comment = end.comment
rs := io.NewSectionReader(r, 0, size)
if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
return 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 {
+
+ // The count of files inside a zip is truncated to fit in a uint16.
+ // Gloss over this by reading headers until we encounter
+ // a bad one, and then only report a FormatError or UnexpectedEOF if
+ // the file count modulo 65536 is incorrect.
+ for {
+ f := &File{zipr: r, zipsize: size}
+ err = readDirectoryHeader(f, buf)
+ if err == FormatError || err == io.ErrUnexpectedEOF {
+ break
+ }
+ if err != nil {
return err
}
+ z.File = append(z.File, f)
+ }
+ if uint16(len(z.File)) != end.directoryRecords {
+ // Return the readDirectoryHeader error if we read
+ // the wrong number of directory entries.
+ return err
}
return nil
}
@@ -109,31 +115,22 @@ func (rc *ReadCloser) Close() os.Error {
}
// Open returns a ReadCloser that provides access to the File's contents.
+// It is safe to Open and Read from files concurrently.
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, os.SEEK_CUR); err != nil {
- return
- }
+ bodyOffset, err := f.findBodyOffset()
+ if err != nil {
+ return
}
size := int64(f.CompressedSize)
- if f.hasDataDescriptor() {
- if size == 0 {
- // permit SectionReader to see the rest of the file
- size = f.zipsize - (off + f.bodyOffset)
- } else {
- size += dataDescriptorLen
- }
+ if size == 0 && f.hasDataDescriptor() {
+ // permit SectionReader to see the rest of the file
+ size = f.zipsize - (f.headerOffset + bodyOffset)
}
- r := io.NewSectionReader(f.zipr, off+f.bodyOffset, size)
+ r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
switch f.Method {
- case 0: // store (no compression)
+ case Store: // (no compression)
rc = ioutil.NopCloser(r)
- case 8: // DEFLATE
+ case Deflate:
rc = flate.NewReader(r)
default:
err = UnsupportedMethod
@@ -170,90 +167,102 @@ func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
func (r *checksumReader) Close() os.Error { return r.rc.Close() }
-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 {
+func readFileHeader(f *File, r io.Reader) os.Error {
+ var b [fileHeaderLen]byte
+ if _, err := io.ReadFull(r, b[:]); err != nil {
+ return err
+ }
+ c := binary.LittleEndian
+ if sig := c.Uint32(b[:4]); sig != 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
+ f.ReaderVersion = c.Uint16(b[4:6])
+ f.Flags = c.Uint16(b[6:8])
+ f.Method = c.Uint16(b[8:10])
+ f.ModifiedTime = c.Uint16(b[10:12])
+ f.ModifiedDate = c.Uint16(b[12:14])
+ f.CRC32 = c.Uint32(b[14:18])
+ f.CompressedSize = c.Uint32(b[18:22])
+ f.UncompressedSize = c.Uint32(b[22:26])
+ filenameLen := int(c.Uint16(b[26:28]))
+ extraLen := int(c.Uint16(b[28:30]))
+ d := make([]byte, filenameLen+extraLen)
+ if _, err := io.ReadFull(r, d); err != nil {
+ return err
+ }
+ f.Name = string(d[:filenameLen])
+ f.Extra = d[filenameLen:]
+ return nil
}
-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 {
+// findBodyOffset does the minimum work to verify the file has a header
+// and returns the file body offset.
+func (f *File) findBodyOffset() (int64, os.Error) {
+ r := io.NewSectionReader(f.zipr, f.headerOffset, f.zipsize-f.headerOffset)
+ var b [fileHeaderLen]byte
+ if _, err := io.ReadFull(r, b[:]); err != nil {
+ return 0, err
+ }
+ c := binary.LittleEndian
+ if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
+ return 0, FormatError
+ }
+ filenameLen := int(c.Uint16(b[26:28]))
+ extraLen := int(c.Uint16(b[28:30]))
+ return int64(fileHeaderLen + filenameLen + extraLen), nil
+}
+
+// readDirectoryHeader attempts to read a directory header from r.
+// It returns io.ErrUnexpectedEOF if it cannot read a complete header,
+// and FormatError if it doesn't find a valid header signature.
+func readDirectoryHeader(f *File, r io.Reader) os.Error {
+ var b [directoryHeaderLen]byte
+ if _, err := io.ReadFull(r, b[:]); err != nil {
+ return err
+ }
+ c := binary.LittleEndian
+ if sig := c.Uint32(b[:4]); sig != 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
+ f.CreatorVersion = c.Uint16(b[4:6])
+ f.ReaderVersion = c.Uint16(b[6:8])
+ f.Flags = c.Uint16(b[8:10])
+ f.Method = c.Uint16(b[10:12])
+ f.ModifiedTime = c.Uint16(b[12:14])
+ f.ModifiedDate = c.Uint16(b[14:16])
+ f.CRC32 = c.Uint32(b[16:20])
+ f.CompressedSize = c.Uint32(b[20:24])
+ f.UncompressedSize = c.Uint32(b[24:28])
+ filenameLen := int(c.Uint16(b[28:30]))
+ extraLen := int(c.Uint16(b[30:32]))
+ commentLen := int(c.Uint16(b[32:34]))
+ // startDiskNumber := c.Uint16(b[34:36]) // Unused
+ // internalAttributes := c.Uint16(b[36:38]) // Unused
+ // externalAttributes := c.Uint32(b[38:42]) // Unused
+ f.headerOffset = int64(c.Uint32(b[42:46]))
+ d := make([]byte, filenameLen+extraLen+commentLen)
+ if _, err := io.ReadFull(r, d); err != nil {
+ return err
+ }
+ f.Name = string(d[:filenameLen])
+ f.Extra = d[filenameLen : filenameLen+extraLen]
+ f.Comment = string(d[filenameLen+extraLen:])
+ return nil
}
-func readDataDescriptor(r io.Reader, f *File) (err os.Error) {
- defer func() {
- if rerr, ok := recover().(os.Error); ok {
- err = rerr
- }
- }()
- read(r, &f.CRC32)
- read(r, &f.CompressedSize)
- read(r, &f.UncompressedSize)
- return
+func readDataDescriptor(r io.Reader, f *File) os.Error {
+ var b [dataDescriptorLen]byte
+ if _, err := io.ReadFull(r, b[:]); err != nil {
+ return err
+ }
+ c := binary.LittleEndian
+ f.CRC32 = c.Uint32(b[:4])
+ f.CompressedSize = c.Uint32(b[4:8])
+ f.UncompressedSize = c.Uint32(b[8:12])
+ return nil
}
-func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) {
+func readDirectoryEnd(r io.ReaderAt, size int64) (dir *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} {
@@ -274,53 +283,29 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error)
}
// 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))
+ c := binary.LittleEndian
+ d := new(directoryEnd)
+ d.diskNbr = c.Uint16(b[4:6])
+ d.dirDiskNbr = c.Uint16(b[6:8])
+ d.dirRecordsThisDisk = c.Uint16(b[8:10])
+ d.directoryRecords = c.Uint16(b[10:12])
+ d.directorySize = c.Uint32(b[12:16])
+ d.directoryOffset = c.Uint32(b[16:20])
+ d.commentLen = c.Uint16(b[20:22])
+ d.comment = string(b[22 : 22+int(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-- {
+ for i := len(b) - directoryEndLen; 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) {
+ n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
+ if n+directoryEndLen+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
index c72cd9a2347..fd5fed2af05 100644
--- a/libgo/go/archive/zip/reader_test.go
+++ b/libgo/go/archive/zip/reader_test.go
@@ -11,6 +11,7 @@ import (
"io/ioutil"
"os"
"testing"
+ "time"
)
type ZipTest struct {
@@ -24,8 +25,19 @@ 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/)
+ Mtime string // modified time in format "mm-dd-yy hh:mm:ss"
}
+// Caution: The Mtime values found for the test files should correspond to
+// the values listed with unzip -l <zipfile>. However, the values
+// listed by unzip appear to be off by some hours. When creating
+// fresh test files and testing them, this issue is not present.
+// The test files were created in Sydney, so there might be a time
+// zone issue. The time zone information does have to be encoded
+// somewhere, because otherwise unzip -l could not provide a different
+// time from what the archive/zip package provides, but there appears
+// to be no documentation about this.
+
var tests = []ZipTest{
{
Name: "test.zip",
@@ -34,10 +46,12 @@ var tests = []ZipTest{
{
Name: "test.txt",
Content: []byte("This is a test text file.\n"),
+ Mtime: "09-05-10 12:12:02",
},
{
- Name: "gophercolor16x16.png",
- File: "gophercolor16x16.png",
+ Name: "gophercolor16x16.png",
+ File: "gophercolor16x16.png",
+ Mtime: "09-05-10 15:52:58",
},
},
},
@@ -45,8 +59,9 @@ var tests = []ZipTest{
Name: "r.zip",
File: []ZipTestFile{
{
- Name: "r/r.zip",
- File: "r.zip",
+ Name: "r/r.zip",
+ File: "r.zip",
+ Mtime: "03-04-10 00:24:16",
},
},
},
@@ -58,6 +73,7 @@ var tests = []ZipTest{
{
Name: "filename",
Content: []byte("This is a test textfile.\n"),
+ Mtime: "02-02-11 13:06:20",
},
},
},
@@ -136,18 +152,36 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
if f.Name != ft.Name {
t.Errorf("name=%q, want %q", f.Name, ft.Name)
}
+
+ mtime, err := time.Parse("01-02-06 15:04:05", ft.Mtime)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if got, want := f.Mtime_ns()/1e9, mtime.Seconds(); got != want {
+ t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want)
+ }
+
+ size0 := f.UncompressedSize
+
var b bytes.Buffer
r, err := f.Open()
if err != nil {
t.Error(err)
return
}
+
+ if size1 := f.UncompressedSize; size0 != size1 {
+ t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1)
+ }
+
_, 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
@@ -155,10 +189,12 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
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])
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
index bfe0aae2e9a..1d6e70f105a 100644
--- a/libgo/go/archive/zip/struct.go
+++ b/libgo/go/archive/zip/struct.go
@@ -1,9 +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 zip provides support for reading and writing ZIP archives.
+
+See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+This package does not support ZIP64 or disk spanning.
+*/
package zip
+import "os"
+import "time"
+
+// Compression methods.
+const (
+ Store uint16 = 0
+ Deflate uint16 = 8
+)
+
const (
fileHeaderSignature = 0x04034b50
directoryHeaderSignature = 0x02014b50
directoryEndSignature = 0x06054b50
+ fileHeaderLen = 30 // + filename + extra
+ directoryHeaderLen = 46 // + filename + extra + comment
+ directoryEndLen = 22 // + comment
dataDescriptorLen = 12
)
@@ -13,8 +36,8 @@ type FileHeader struct {
ReaderVersion uint16
Flags uint16
Method uint16
- ModifiedTime uint16
- ModifiedDate uint16
+ ModifiedTime uint16 // MS-DOS time
+ ModifiedDate uint16 // MS-DOS date
CRC32 uint32
CompressedSize uint32
UncompressedSize uint32
@@ -32,3 +55,37 @@ type directoryEnd struct {
commentLen uint16
comment string
}
+
+func recoverError(err *os.Error) {
+ if e := recover(); e != nil {
+ if osErr, ok := e.(os.Error); ok {
+ *err = osErr
+ return
+ }
+ panic(e)
+ }
+}
+
+// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
+// The resolution is 2s.
+// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
+func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
+ return time.Time{
+ // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
+ Year: int64(dosDate>>9 + 1980),
+ Month: int(dosDate >> 5 & 0xf),
+ Day: int(dosDate & 0x1f),
+
+ // time bits 0-4: second/2; 5-10: minute; 11-15: hour
+ Hour: int(dosTime >> 11),
+ Minute: int(dosTime >> 5 & 0x3f),
+ Second: int(dosTime & 0x1f * 2),
+ }
+}
+
+// Mtime_ns returns the modified time in ns since epoch.
+// The resolution is 2s.
+func (h *FileHeader) Mtime_ns() int64 {
+ t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
+ return t.Seconds() * 1e9
+}
diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go
new file mode 100644
index 00000000000..2065b06daac
--- /dev/null
+++ b/libgo/go/archive/zip/writer.go
@@ -0,0 +1,244 @@
+// 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 zip
+
+import (
+ "bufio"
+ "compress/flate"
+ "encoding/binary"
+ "hash"
+ "hash/crc32"
+ "io"
+ "os"
+)
+
+// TODO(adg): support zip file comments
+// TODO(adg): support specifying deflate level
+
+// Writer implements a zip file writer.
+type Writer struct {
+ *countWriter
+ dir []*header
+ last *fileWriter
+ closed bool
+}
+
+type header struct {
+ *FileHeader
+ offset uint32
+}
+
+// NewWriter returns a new Writer writing a zip file to w.
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{countWriter: &countWriter{w: bufio.NewWriter(w)}}
+}
+
+// Close finishes writing the zip file by writing the central directory.
+// It does not (and can not) close the underlying writer.
+func (w *Writer) Close() (err os.Error) {
+ if w.last != nil && !w.last.closed {
+ if err = w.last.close(); err != nil {
+ return
+ }
+ w.last = nil
+ }
+ if w.closed {
+ return os.NewError("zip: writer closed twice")
+ }
+ w.closed = true
+
+ defer recoverError(&err)
+
+ // write central directory
+ start := w.count
+ for _, h := range w.dir {
+ write(w, uint32(directoryHeaderSignature))
+ write(w, h.CreatorVersion)
+ write(w, h.ReaderVersion)
+ write(w, h.Flags)
+ write(w, h.Method)
+ write(w, h.ModifiedTime)
+ write(w, h.ModifiedDate)
+ write(w, h.CRC32)
+ write(w, h.CompressedSize)
+ write(w, h.UncompressedSize)
+ write(w, uint16(len(h.Name)))
+ write(w, uint16(len(h.Extra)))
+ write(w, uint16(len(h.Comment)))
+ write(w, uint16(0)) // disk number start
+ write(w, uint16(0)) // internal file attributes
+ write(w, uint32(0)) // external file attributes
+ write(w, h.offset)
+ writeBytes(w, []byte(h.Name))
+ writeBytes(w, h.Extra)
+ writeBytes(w, []byte(h.Comment))
+ }
+ end := w.count
+
+ // write end record
+ write(w, uint32(directoryEndSignature))
+ write(w, uint16(0)) // disk number
+ write(w, uint16(0)) // disk number where directory starts
+ write(w, uint16(len(w.dir))) // number of entries this disk
+ write(w, uint16(len(w.dir))) // number of entries total
+ write(w, uint32(end-start)) // size of directory
+ write(w, uint32(start)) // start of directory
+ write(w, uint16(0)) // size of comment
+
+ return w.w.(*bufio.Writer).Flush()
+}
+
+// Create adds a file to the zip file using the provided name.
+// It returns a Writer to which the file contents should be written.
+// The file's contents must be written to the io.Writer before the next
+// call to Create, CreateHeader, or Close.
+func (w *Writer) Create(name string) (io.Writer, os.Error) {
+ header := &FileHeader{
+ Name: name,
+ Method: Deflate,
+ }
+ return w.CreateHeader(header)
+}
+
+// CreateHeader adds a file to the zip file using the provided FileHeader
+// for the file metadata.
+// It returns a Writer to which the file contents should be written.
+// The file's contents must be written to the io.Writer before the next
+// call to Create, CreateHeader, or Close.
+func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, os.Error) {
+ if w.last != nil && !w.last.closed {
+ if err := w.last.close(); err != nil {
+ return nil, err
+ }
+ }
+
+ fh.Flags |= 0x8 // we will write a data descriptor
+ fh.CreatorVersion = 0x14
+ fh.ReaderVersion = 0x14
+
+ fw := &fileWriter{
+ zipw: w,
+ compCount: &countWriter{w: w},
+ crc32: crc32.NewIEEE(),
+ }
+ switch fh.Method {
+ case Store:
+ fw.comp = nopCloser{fw.compCount}
+ case Deflate:
+ fw.comp = flate.NewWriter(fw.compCount, 5)
+ default:
+ return nil, UnsupportedMethod
+ }
+ fw.rawCount = &countWriter{w: fw.comp}
+
+ h := &header{
+ FileHeader: fh,
+ offset: uint32(w.count),
+ }
+ w.dir = append(w.dir, h)
+ fw.header = h
+
+ if err := writeHeader(w, fh); err != nil {
+ return nil, err
+ }
+
+ w.last = fw
+ return fw, nil
+}
+
+func writeHeader(w io.Writer, h *FileHeader) (err os.Error) {
+ defer recoverError(&err)
+ write(w, uint32(fileHeaderSignature))
+ write(w, h.ReaderVersion)
+ write(w, h.Flags)
+ write(w, h.Method)
+ write(w, h.ModifiedTime)
+ write(w, h.ModifiedDate)
+ write(w, h.CRC32)
+ write(w, h.CompressedSize)
+ write(w, h.UncompressedSize)
+ write(w, uint16(len(h.Name)))
+ write(w, uint16(len(h.Extra)))
+ writeBytes(w, []byte(h.Name))
+ writeBytes(w, h.Extra)
+ return nil
+}
+
+type fileWriter struct {
+ *header
+ zipw io.Writer
+ rawCount *countWriter
+ comp io.WriteCloser
+ compCount *countWriter
+ crc32 hash.Hash32
+ closed bool
+}
+
+func (w *fileWriter) Write(p []byte) (int, os.Error) {
+ if w.closed {
+ return 0, os.NewError("zip: write to closed file")
+ }
+ w.crc32.Write(p)
+ return w.rawCount.Write(p)
+}
+
+func (w *fileWriter) close() (err os.Error) {
+ if w.closed {
+ return os.NewError("zip: file closed twice")
+ }
+ w.closed = true
+ if err = w.comp.Close(); err != nil {
+ return
+ }
+
+ // update FileHeader
+ fh := w.header.FileHeader
+ fh.CRC32 = w.crc32.Sum32()
+ fh.CompressedSize = uint32(w.compCount.count)
+ fh.UncompressedSize = uint32(w.rawCount.count)
+
+ // write data descriptor
+ defer recoverError(&err)
+ write(w.zipw, fh.CRC32)
+ write(w.zipw, fh.CompressedSize)
+ write(w.zipw, fh.UncompressedSize)
+
+ return nil
+}
+
+type countWriter struct {
+ w io.Writer
+ count int64
+}
+
+func (w *countWriter) Write(p []byte) (int, os.Error) {
+ n, err := w.w.Write(p)
+ w.count += int64(n)
+ return n, err
+}
+
+type nopCloser struct {
+ io.Writer
+}
+
+func (w nopCloser) Close() os.Error {
+ return nil
+}
+
+func write(w io.Writer, data interface{}) {
+ if err := binary.Write(w, binary.LittleEndian, data); err != nil {
+ panic(err)
+ }
+}
+
+func writeBytes(w io.Writer, b []byte) {
+ n, err := w.Write(b)
+ if err != nil {
+ panic(err)
+ }
+ if n != len(b) {
+ panic(io.ErrShortWrite)
+ }
+}
diff --git a/libgo/go/archive/zip/writer_test.go b/libgo/go/archive/zip/writer_test.go
new file mode 100644
index 00000000000..eb2a80c3f70
--- /dev/null
+++ b/libgo/go/archive/zip/writer_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip
+
+import (
+ "bytes"
+ "io/ioutil"
+ "rand"
+ "testing"
+)
+
+// TODO(adg): a more sophisticated test suite
+
+const testString = "Rabbits, guinea pigs, gophers, marsupial rats, and quolls."
+
+func TestWriter(t *testing.T) {
+ largeData := make([]byte, 1<<17)
+ for i := range largeData {
+ largeData[i] = byte(rand.Int())
+ }
+
+ // write a zip file
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf)
+ testCreate(t, w, "foo", []byte(testString), Store)
+ testCreate(t, w, "bar", largeData, Deflate)
+ if err := w.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ // read it back
+ r, err := NewReader(sliceReaderAt(buf.Bytes()), int64(buf.Len()))
+ if err != nil {
+ t.Fatal(err)
+ }
+ testReadFile(t, r.File[0], []byte(testString))
+ testReadFile(t, r.File[1], largeData)
+}
+
+func testCreate(t *testing.T, w *Writer, name string, data []byte, method uint16) {
+ header := &FileHeader{
+ Name: name,
+ Method: method,
+ }
+ f, err := w.CreateHeader(header)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.Write(data)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testReadFile(t *testing.T, f *File, data []byte) {
+ rc, err := f.Open()
+ if err != nil {
+ t.Fatal("opening:", err)
+ }
+ b, err := ioutil.ReadAll(rc)
+ if err != nil {
+ t.Fatal("reading:", err)
+ }
+ err = rc.Close()
+ if err != nil {
+ t.Fatal("closing:", err)
+ }
+ if !bytes.Equal(b, data) {
+ t.Errorf("File contents %q, want %q", b, data)
+ }
+}
diff --git a/libgo/go/archive/zip/zip_test.go b/libgo/go/archive/zip/zip_test.go
new file mode 100644
index 00000000000..0f71fdfac17
--- /dev/null
+++ b/libgo/go/archive/zip/zip_test.go
@@ -0,0 +1,57 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests that involve both reading and writing.
+
+package zip
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "testing"
+)
+
+type stringReaderAt string
+
+func (s stringReaderAt) ReadAt(p []byte, off int64) (n int, err os.Error) {
+ if off >= int64(len(s)) {
+ return 0, os.EOF
+ }
+ n = copy(p, s[off:])
+ return
+}
+
+func TestOver65kFiles(t *testing.T) {
+ if testing.Short() {
+ t.Logf("slow test; skipping")
+ return
+ }
+ buf := new(bytes.Buffer)
+ w := NewWriter(buf)
+ const nFiles = (1 << 16) + 42
+ for i := 0; i < nFiles; i++ {
+ _, err := w.Create(fmt.Sprintf("%d.dat", i))
+ if err != nil {
+ t.Fatalf("creating file %d: %v", i, err)
+ }
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close: %v", err)
+ }
+ rat := stringReaderAt(buf.String())
+ zr, err := NewReader(rat, int64(len(rat)))
+ if err != nil {
+ t.Fatalf("NewReader: %v", err)
+ }
+ if got := len(zr.File); got != nFiles {
+ t.Fatalf("File contains %d files, want %d", got, nFiles)
+ }
+ for i := 0; i < nFiles; i++ {
+ want := fmt.Sprintf("%d.dat", i)
+ if zr.File[i].Name != want {
+ t.Fatalf("File(%d) = %q, want %q", i, zr.File[i].Name, want)
+ }
+ }
+}
diff --git a/libgo/go/asn1/asn1.go b/libgo/go/asn1/asn1.go
index 5f470aed797..39b676b4190 100644
--- a/libgo/go/asn1/asn1.go
+++ b/libgo/go/asn1/asn1.go
@@ -20,6 +20,7 @@ package asn1
// everything by any means.
import (
+ "big"
"fmt"
"os"
"reflect"
@@ -88,6 +89,27 @@ func parseInt(bytes []byte) (int, os.Error) {
return int(ret64), nil
}
+var bigOne = big.NewInt(1)
+
+// parseBigInt treats the given bytes as a big-endian, signed integer and returns
+// the result.
+func parseBigInt(bytes []byte) *big.Int {
+ ret := new(big.Int)
+ if len(bytes) > 0 && bytes[0]&0x80 == 0x80 {
+ // This is a negative number.
+ notBytes := make([]byte, len(bytes))
+ for i := range notBytes {
+ notBytes[i] = ^bytes[i]
+ }
+ ret.SetBytes(notBytes)
+ ret.Add(ret, bigOne)
+ ret.Neg(ret)
+ return ret
+ }
+ ret.SetBytes(bytes)
+ return ret
+}
+
// BIT STRING
// BitString is the structure to use when you want an ASN.1 BIT STRING type. A
@@ -127,7 +149,7 @@ func (b BitString) RightAlign() []byte {
return a
}
-// parseBitString parses an ASN.1 bit string from the given byte array and returns it.
+// parseBitString parses an ASN.1 bit string from the given byte slice and returns it.
func parseBitString(bytes []byte) (ret BitString, err os.Error) {
if len(bytes) == 0 {
err = SyntaxError{"zero length BIT STRING"}
@@ -164,9 +186,9 @@ func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
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.
+// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
+// returns it. An object identifier is a sequence of variable length integers
+// that are assigned in a hierarchy.
func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
if len(bytes) == 0 {
err = SyntaxError{"zero length OBJECT IDENTIFIER"}
@@ -198,14 +220,13 @@ func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
// 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.
+// given byte slice. 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++ {
@@ -237,7 +258,7 @@ func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
return
}
-// parseGeneralizedTime parses the GeneralizedTime from the given byte array
+// parseGeneralizedTime parses the GeneralizedTime from the given byte slice
// and returns the resulting time.
func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
return time.Parse("20060102150405Z0700", string(bytes))
@@ -269,7 +290,7 @@ func isPrintable(b byte) bool {
b == ':' ||
b == '=' ||
b == '?' ||
- // This is techincally not allowed in a PrintableString.
+ // This is technically not allowed in a PrintableString.
// However, x509 certificates with wildcard strings don't
// always use the correct string type so we permit it.
b == '*'
@@ -278,7 +299,7 @@ func isPrintable(b byte) bool {
// IA5String
// parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
-// byte array and returns it.
+// byte slice and returns it.
func parseIA5String(bytes []byte) (ret string, err os.Error) {
for _, b := range bytes {
if b >= 0x80 {
@@ -293,11 +314,19 @@ func parseIA5String(bytes []byte) (ret string, err os.Error) {
// T61String
// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
-// byte array and returns it.
+// byte slice and returns it.
func parseT61String(bytes []byte) (ret string, err os.Error) {
return string(bytes), nil
}
+// UTF8String
+
+// parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte
+// array and returns it.
+func parseUTF8String(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
@@ -314,7 +343,7 @@ 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
+// into a byte slice. 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) {
@@ -371,7 +400,7 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
}
// 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
+// a number of ASN.1 values from the given byte slice and returns them as a
// slice of Go values of the given type.
func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err os.Error) {
expectedTag, compoundType, ok := getUniversalType(elemType)
@@ -425,6 +454,7 @@ var (
timeType = reflect.TypeOf(&time.Time{})
rawValueType = reflect.TypeOf(RawValue{})
rawContentsType = reflect.TypeOf(RawContent(nil))
+ bigIntType = reflect.TypeOf(new(big.Int))
)
// invalidLength returns true iff offset + length > sliceLength, or if the
@@ -433,7 +463,7 @@ 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
+// parseField is the main parsing function. Given a byte slice 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) {
@@ -550,16 +580,15 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
}
}
- // 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
- }
- // Likewise for GeneralString
- if universalTag == tagPrintableString && t.tag == tagGeneralString {
- universalTag = tagGeneralString
+ // Special case for strings: all the ASN.1 string types map to the Go
+ // type string. getUniversalType returns the tag for PrintableString
+ // when it sees a string, so if we see a different string type on the
+ // wire, we change the universal type to match.
+ if universalTag == tagPrintableString {
+ switch t.tag {
+ case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+ universalTag = t.tag
+ }
}
// Special case for time: UTCTime and GeneralizedTime both map to the
@@ -639,6 +668,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
case flagType:
v.SetBool(true)
return
+ case bigIntType:
+ parsedInt := parseBigInt(innerBytes)
+ v.Set(reflect.ValueOf(parsedInt))
+ return
}
switch val := v; val.Kind() {
case reflect.Bool:
@@ -648,23 +681,21 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
}
err = err1
return
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- switch val.Type().Kind() {
- case reflect.Int:
- parsedInt, err1 := parseInt(innerBytes)
- if err1 == nil {
- val.SetInt(int64(parsedInt))
- }
- err = err1
- return
- case reflect.Int64:
- parsedInt, err1 := parseInt64(innerBytes)
- if err1 == nil {
- val.SetInt(parsedInt)
- }
- err = err1
- return
+ case reflect.Int, reflect.Int32:
+ parsedInt, err1 := parseInt(innerBytes)
+ if err1 == nil {
+ val.SetInt(int64(parsedInt))
}
+ err = err1
+ return
+ case reflect.Int64:
+ parsedInt, err1 := parseInt64(innerBytes)
+ if err1 == nil {
+ val.SetInt(parsedInt)
+ }
+ err = err1
+ return
+ // TODO(dfc) Add support for the remaining integer types
case reflect.Struct:
structType := fieldType
@@ -680,7 +711,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
if i == 0 && field.Type == rawContentsType {
continue
}
- innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag))
+ innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag.Get("asn1")))
if err != nil {
return
}
@@ -711,6 +742,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
v, err = parseIA5String(innerBytes)
case tagT61String:
v, err = parseT61String(innerBytes)
+ case tagUTF8String:
+ v, err = parseUTF8String(innerBytes)
case tagGeneralString:
// GeneralString is specified in ISO-2022/ECMA-35,
// A brief review suggests that it includes structures
@@ -725,7 +758,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
}
return
}
- err = StructuralError{"unknown Go type"}
+ err = StructuralError{"unsupported: " + v.Type().String()}
return
}
@@ -752,7 +785,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
// 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.
+// An ASN.1 INTEGER can be written to an int, int32 or int64.
// If the encoded value does not fit in the Go type,
// Unmarshal returns a parse error.
//
diff --git a/libgo/go/asn1/asn1_test.go b/libgo/go/asn1/asn1_test.go
index 78f56280524..9f48f7bdd5d 100644
--- a/libgo/go/asn1/asn1_test.go
+++ b/libgo/go/asn1/asn1_test.go
@@ -42,6 +42,64 @@ func TestParseInt64(t *testing.T) {
}
}
+type int32Test struct {
+ in []byte
+ ok bool
+ out int32
+}
+
+var int32TestData = []int32Test{
+ {[]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}, true, -1},
+ {[]byte{0xff}, true, -1},
+ {[]byte{0x80, 0x00, 0x00, 0x00}, true, -2147483648},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00}, false, 0},
+}
+
+func TestParseInt32(t *testing.T) {
+ for i, test := range int32TestData {
+ ret, err := parseInt(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 && int32(ret) != test.out {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+}
+
+var bigIntTests = []struct {
+ in []byte
+ base10 string
+}{
+ {[]byte{0xff}, "-1"},
+ {[]byte{0x00}, "0"},
+ {[]byte{0x01}, "1"},
+ {[]byte{0x00, 0xff}, "255"},
+ {[]byte{0xff, 0x00}, "-256"},
+ {[]byte{0x01, 0x00}, "256"},
+}
+
+func TestParseBigInt(t *testing.T) {
+ for i, test := range bigIntTests {
+ ret := parseBigInt(test.in)
+ if ret.String() != test.base10 {
+ t.Errorf("#%d: bad result from %x, got %s want %s", i, test.in, ret.String(), test.base10)
+ }
+ fw := newForkableWriter()
+ marshalBigInt(fw, ret)
+ result := fw.Bytes()
+ if !bytes.Equal(result, test.in) {
+ t.Errorf("#%d: got %x from marshaling %s, want %x", i, result, ret, test.in)
+ }
+ }
+}
+
type bitStringTest struct {
in []byte
ok bool
@@ -148,10 +206,10 @@ type timeTest struct {
}
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"}},
+ {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 0, -7 * 60 * 60, ""}},
+ {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 0, 7*60*60 + 30*60, ""}},
+ {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, 0, "UTC"}},
+ {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, 0, "UTC"}},
{"a10506234540Z", false, nil},
{"91a506234540Z", false, nil},
{"9105a6234540Z", false, nil},
@@ -177,10 +235,10 @@ func TestUTCTime(t *testing.T) {
}
var generalizedTimeTestData = []timeTest{
- {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, "UTC"}},
+ {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 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, ""}},
+ {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, 6*60*60 + 7*60, ""}},
+ {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, -6*60*60 - 7*60, ""}},
}
func TestGeneralizedTime(t *testing.T) {
@@ -272,11 +330,11 @@ type TestObjectIdentifierStruct struct {
}
type TestContextSpecificTags struct {
- A int "tag:1"
+ A int `asn1:"tag:1"`
}
type TestContextSpecificTags2 struct {
- A int "explicit,tag:1"
+ A int `asn1:"explicit,tag:1"`
B int
}
@@ -326,7 +384,7 @@ type Certificate struct {
}
type TBSCertificate struct {
- Version int "optional,explicit,default:0,tag:0"
+ Version int `asn1:"optional,explicit,default:0,tag:0"`
SerialNumber RawValue
SignatureAlgorithm AlgorithmIdentifier
Issuer RDNSequence
diff --git a/libgo/go/asn1/common.go b/libgo/go/asn1/common.go
index 1589877477c..01f4f7b6ec7 100644
--- a/libgo/go/asn1/common.go
+++ b/libgo/go/asn1/common.go
@@ -10,7 +10,7 @@ import (
"strings"
)
-// ASN.1 objects have metadata preceeding them:
+// ASN.1 objects have metadata preceding 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
@@ -25,6 +25,7 @@ const (
tagOctetString = 4
tagOID = 6
tagEnum = 10
+ tagUTF8String = 12
tagSequence = 16
tagSet = 17
tagPrintableString = 19
@@ -83,7 +84,7 @@ type fieldParameters struct {
// 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) {
+ for _, part := range strings.Split(str, ",") {
switch {
case part == "optional":
ret.optional = true
@@ -132,6 +133,8 @@ func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
return tagUTCTime, false, true
case enumeratedType:
return tagEnum, false, true
+ case bigIntType:
+ return tagInteger, false, true
}
switch t.Kind() {
case reflect.Bool:
diff --git a/libgo/go/asn1/marshal.go b/libgo/go/asn1/marshal.go
index a3e1145b895..d7eb63bf82c 100644
--- a/libgo/go/asn1/marshal.go
+++ b/libgo/go/asn1/marshal.go
@@ -5,6 +5,7 @@
package asn1
import (
+ "big"
"bytes"
"fmt"
"io"
@@ -125,6 +126,43 @@ func int64Length(i int64) (numBytes int) {
return
}
+func marshalBigInt(out *forkableWriter, n *big.Int) (err os.Error) {
+ if n.Sign() < 0 {
+ // A negative number has to be converted to two's-complement
+ // form. So we'll subtract 1 and invert. If the
+ // most-significant-bit isn't set then we'll need to pad the
+ // beginning with 0xff in order to keep the number negative.
+ nMinus1 := new(big.Int).Neg(n)
+ nMinus1.Sub(nMinus1, bigOne)
+ bytes := nMinus1.Bytes()
+ for i := range bytes {
+ bytes[i] ^= 0xff
+ }
+ if len(bytes) == 0 || bytes[0]&0x80 == 0 {
+ err = out.WriteByte(0xff)
+ if err != nil {
+ return
+ }
+ }
+ _, err = out.Write(bytes)
+ } else if n.Sign() == 0 {
+ // Zero is written as a single 0 zero rather than no bytes.
+ err = out.WriteByte(0x00)
+ } else {
+ bytes := n.Bytes()
+ if len(bytes) > 0 && bytes[0]&0x80 != 0 {
+ // We'll have to pad this with 0x00 in order to stop it
+ // looking like a negative number.
+ err = out.WriteByte(0)
+ if err != nil {
+ return
+ }
+ }
+ _, err = out.Write(bytes)
+ }
+ return
+}
+
func marshalLength(out *forkableWriter, i int) (err os.Error) {
n := lengthLength(i)
@@ -334,6 +372,8 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
return marshalBitString(out, value.Interface().(BitString))
case objectIdentifierType:
return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
+ case bigIntType:
+ return marshalBigInt(out, value.Interface().(*big.Int))
}
switch v := value; v.Kind() {
@@ -351,7 +391,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
startingField := 0
// If the first element of the structure is a non-empty
- // RawContents, then we don't bother serialising the rest.
+ // RawContents, then we don't bother serializing the rest.
if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
s := v.Field(0)
if s.Len() > 0 {
@@ -361,7 +401,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
}
/* The RawContents will contain the tag and
* length fields but we'll also be writing
- * those outselves, so we strip them out of
+ * those ourselves, so we strip them out of
* bytes */
_, err = out.Write(stripTagAndLength(bytes))
return
@@ -373,7 +413,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
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))
+ err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1")))
if err != nil {
return
}
@@ -418,6 +458,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return marshalField(out, v.Elem(), params)
}
+ if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
+ return
+ }
+
if v.Type() == rawValueType {
rv := v.Interface().(RawValue)
err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
@@ -428,10 +472,6 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return
}
- if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
- return
- }
-
tag, isCompound, ok := getUniversalType(v.Type())
if !ok {
err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
diff --git a/libgo/go/asn1/marshal_test.go b/libgo/go/asn1/marshal_test.go
index cd165d20352..03df5f1e1d5 100644
--- a/libgo/go/asn1/marshal_test.go
+++ b/libgo/go/asn1/marshal_test.go
@@ -30,19 +30,23 @@ type rawContentsStruct struct {
}
type implicitTagTest struct {
- A int "implicit,tag:5"
+ A int `asn1:"implicit,tag:5"`
}
type explicitTagTest struct {
- A int "explicit,tag:5"
+ A int `asn1:"explicit,tag:5"`
}
type ia5StringTest struct {
- A string "ia5"
+ A string `asn1:"ia5"`
}
type printableStringTest struct {
- A string "printable"
+ A string `asn1:"printable"`
+}
+
+type optionalRawValueTest struct {
+ A RawValue `asn1:"optional"`
}
type testSET []int
@@ -102,6 +106,7 @@ var marshalTests = []marshalTest{
"7878787878787878787878787878787878787878787878787878787878787878",
},
{ia5StringTest{"test"}, "3006160474657374"},
+ {optionalRawValueTest{}, "3000"},
{printableStringTest{"test"}, "3006130474657374"},
{printableStringTest{"test*"}, "30071305746573742a"},
{rawContentsStruct{nil, 64}, "3003020140"},
diff --git a/libgo/go/big/arith.go b/libgo/go/big/arith.go
index a4048d6d751..242bd1e8cc4 100644
--- a/libgo/go/big/arith.go
+++ b/libgo/go/big/arith.go
@@ -27,7 +27,6 @@ const (
_M2 = _B2 - 1 // half digit mask
)
-
// ----------------------------------------------------------------------------
// Elementary operations on words
//
@@ -43,7 +42,6 @@ func addWW_g(x, y, c Word) (z1, z0 Word) {
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
@@ -54,7 +52,6 @@ func subWW_g(x, y, c Word) (z1, z0 Word) {
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.
@@ -73,7 +70,6 @@ func mulWW_g(x, y Word) (z1, z0 Word) {
return
}
-
// z1<<_W + z0 = x*y + c
func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
z1, zz0 := mulWW(x, y)
@@ -83,7 +79,6 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
return
}
-
// Length of x in bits.
func bitLen(x Word) (n int) {
for ; x >= 0x100; x >>= 8 {
@@ -95,7 +90,6 @@ func bitLen(x Word) (n int) {
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.
@@ -103,13 +97,11 @@ 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.
@@ -155,7 +147,6 @@ 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 {
@@ -164,7 +155,6 @@ func addVV_g(z, x, y []Word) (c Word) {
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 {
@@ -173,7 +163,6 @@ func subVV_g(z, x, y []Word) (c Word) {
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
@@ -183,7 +172,6 @@ func addVW_g(z, x []Word, y Word) (c Word) {
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
@@ -193,9 +181,8 @@ func subVW_g(z, x []Word, y Word) (c Word) {
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) {
+func shlVU(z, x []Word, s uint) (c Word) { return shlVU_g(z, x, s) }
+func shlVU_g(z, x []Word, s uint) (c Word) {
if n := len(z); n > 0 {
ŝ := _W - s
w1 := x[n-1]
@@ -210,9 +197,8 @@ func shlVW_g(z, x []Word, s Word) (c Word) {
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) {
+func shrVU(z, x []Word, s uint) (c Word) { return shrVU_g(z, x, s) }
+func shrVU_g(z, x []Word, s uint) (c Word) {
if n := len(z); n > 0 {
ŝ := _W - s
w1 := x[0]
@@ -227,7 +213,6 @@ func shrVW_g(z, x []Word, s Word) (c Word) {
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
@@ -237,7 +222,6 @@ func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
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 {
@@ -248,7 +232,6 @@ func addMulVVW_g(z, x []Word, y Word) (c Word) {
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
diff --git a/libgo/go/big/arith_decl.go b/libgo/go/big/arith_decl.go
index c456d5f67d3..95fcd8b94be 100644
--- a/libgo/go/big/arith_decl.go
+++ b/libgo/go/big/arith_decl.go
@@ -11,8 +11,8 @@ 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 shlVU(z, x []Word, s uint) (c Word)
+func shrVU(z, x []Word, s uint) (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
index 934b302df03..b6c56c39ef4 100644
--- a/libgo/go/big/arith_test.go
+++ b/libgo/go/big/arith_test.go
@@ -6,7 +6,6 @@ package big
import "testing"
-
type funWW func(x, y, c Word) (z1, z0 Word)
type argWW struct {
x, y, c, z1, z0 Word
@@ -26,7 +25,6 @@ var sumWW = []argWW{
{_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 {
@@ -34,7 +32,6 @@ func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
}
}
-
func TestFunWW(t *testing.T) {
for _, a := range sumWW {
arg := a
@@ -51,7 +48,6 @@ func TestFunWW(t *testing.T) {
}
}
-
type funVV func(z, x, y []Word) (c Word)
type argVV struct {
z, x, y nat
@@ -70,7 +66,6 @@ var sumVV = []argVV{
{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)
@@ -85,7 +80,6 @@ func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
}
}
-
func TestFunVV(t *testing.T) {
for _, a := range sumVV {
arg := a
@@ -106,7 +100,6 @@ func TestFunVV(t *testing.T) {
}
}
-
type funVW func(z, x []Word, y Word) (c Word)
type argVW struct {
z, x nat
@@ -169,7 +162,6 @@ var rshVW = []argVW{
{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)
@@ -184,6 +176,11 @@ func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
}
}
+func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW {
+ return func(z, x []Word, s Word) (c Word) {
+ return f(z, x, uint(s))
+ }
+}
func TestFunVW(t *testing.T) {
for _, a := range sumVW {
@@ -196,20 +193,23 @@ func TestFunVW(t *testing.T) {
testFunVW(t, "subVW", subVW, arg)
}
+ shlVW_g := makeFunVW(shlVU_g)
+ shlVW := makeFunVW(shlVU)
for _, a := range lshVW {
arg := a
- testFunVW(t, "shlVW_g", shlVW_g, arg)
- testFunVW(t, "shlVW", shlVW, arg)
+ testFunVW(t, "shlVU_g", shlVW_g, arg)
+ testFunVW(t, "shlVU", shlVW, arg)
}
+ shrVW_g := makeFunVW(shrVU_g)
+ shrVW := makeFunVW(shrVU)
for _, a := range rshVW {
arg := a
- testFunVW(t, "shrVW_g", shrVW_g, arg)
- testFunVW(t, "shrVW", shrVW, arg)
+ testFunVW(t, "shrVU_g", shrVW_g, arg)
+ testFunVW(t, "shrVU", shrVW, arg)
}
}
-
type funVWW func(z, x []Word, y, r Word) (c Word)
type argVWW struct {
z, x nat
@@ -243,7 +243,6 @@ var prodVWW = []argVWW{
{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)
@@ -258,7 +257,6 @@ func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
}
}
-
// TODO(gri) mulAddVWW and divWVW are symmetric operations but
// their signature is not symmetric. Try to unify.
@@ -285,7 +283,6 @@ func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
}
}
-
func TestFunVWW(t *testing.T) {
for _, a := range prodVWW {
arg := a
@@ -300,7 +297,6 @@ func TestFunVWW(t *testing.T) {
}
}
-
var mulWWTests = []struct {
x, y Word
q, r Word
@@ -309,7 +305,6 @@ var mulWWTests = []struct {
// 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)
@@ -319,7 +314,6 @@ func TestMulWW(t *testing.T) {
}
}
-
var mulAddWWWTests = []struct {
x, y, c Word
q, r Word
@@ -331,7 +325,6 @@ var mulAddWWWTests = []struct {
{_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)
diff --git a/libgo/go/big/calibrate_test.go b/libgo/go/big/calibrate_test.go
index c6cd2e693b7..1cd93b1052b 100644
--- a/libgo/go/big/calibrate_test.go
+++ b/libgo/go/big/calibrate_test.go
@@ -19,10 +19,8 @@ import (
"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
@@ -34,7 +32,6 @@ func measure(f func()) int64 {
return (stop - start) / N
}
-
func computeThresholds() {
fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
fmt.Printf("(run repeatedly for good results)\n")
@@ -84,7 +81,6 @@ func computeThresholds() {
}
}
-
func TestCalibrate(t *testing.T) {
if *calibrate {
computeThresholds()
diff --git a/libgo/go/big/hilbert_test.go b/libgo/go/big/hilbert_test.go
index 66a21214d22..1a84341b3c0 100644
--- a/libgo/go/big/hilbert_test.go
+++ b/libgo/go/big/hilbert_test.go
@@ -13,13 +13,11 @@ import (
"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")
@@ -27,7 +25,6 @@ func (a *matrix) at(i, j int) *Rat {
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")
@@ -35,7 +32,6 @@ func (a *matrix) set(i, j int, x *Rat) {
a.a[i*a.m+j] = x
}
-
func newMatrix(n, m int) *matrix {
if !(0 <= n && 0 <= m) {
panic("illegal matrix")
@@ -47,7 +43,6 @@ func newMatrix(n, m int) *matrix {
return a
}
-
func newUnit(n int) *matrix {
a := newMatrix(n, n)
for i := 0; i < n; i++ {
@@ -62,7 +57,6 @@ func newUnit(n int) *matrix {
return a
}
-
func newHilbert(n int) *matrix {
a := newMatrix(n, n)
for i := 0; i < n; i++ {
@@ -73,7 +67,6 @@ func newHilbert(n int) *matrix {
return a
}
-
func newInverseHilbert(n int) *matrix {
a := newMatrix(n, n)
for i := 0; i < n; i++ {
@@ -98,7 +91,6 @@ func newInverseHilbert(n int) *matrix {
return a
}
-
func (a *matrix) mul(b *matrix) *matrix {
if a.m != b.n {
panic("illegal matrix multiply")
@@ -116,7 +108,6 @@ func (a *matrix) mul(b *matrix) *matrix {
return c
}
-
func (a *matrix) eql(b *matrix) bool {
if a.n != b.n || a.m != b.m {
return false
@@ -131,7 +122,6 @@ func (a *matrix) eql(b *matrix) bool {
return true
}
-
func (a *matrix) String() string {
s := ""
for i := 0; i < a.n; i++ {
@@ -143,7 +133,6 @@ func (a *matrix) String() string {
return s
}
-
func doHilbert(t *testing.T, n int) {
a := newHilbert(n)
b := newInverseHilbert(n)
@@ -160,12 +149,10 @@ func doHilbert(t *testing.T, n int) {
}
}
-
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
index f1ea7b1c2ec..701b69715db 100644
--- a/libgo/go/big/int.go
+++ b/libgo/go/big/int.go
@@ -8,8 +8,10 @@ package big
import (
"fmt"
+ "io"
"os"
"rand"
+ "strings"
)
// An Int represents a signed multi-precision integer.
@@ -19,10 +21,8 @@ type Int struct {
abs nat // absolute value of the integer
}
-
var intOne = &Int{false, natOne}
-
// Sign returns:
//
// -1 if x < 0
@@ -39,7 +39,6 @@ func (x *Int) Sign() int {
return 1
}
-
// SetInt64 sets z to x and returns z.
func (z *Int) SetInt64(x int64) *Int {
neg := false
@@ -52,13 +51,11 @@ func (z *Int) SetInt64(x int64) *Int {
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)
@@ -66,7 +63,6 @@ func (z *Int) Set(x *Int) *Int {
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)
@@ -74,7 +70,6 @@ func (z *Int) Abs(x *Int) *Int {
return z
}
-
// Neg sets z to -x and returns z.
func (z *Int) Neg(x *Int) *Int {
z.abs = z.abs.set(x.abs)
@@ -82,7 +77,6 @@ func (z *Int) Neg(x *Int) *Int {
return z
}
-
// Add sets z to the sum x+y and returns z.
func (z *Int) Add(x, y *Int) *Int {
neg := x.neg
@@ -104,7 +98,6 @@ func (z *Int) Add(x, y *Int) *Int {
return z
}
-
// Sub sets z to the difference x-y and returns z.
func (z *Int) Sub(x, y *Int) *Int {
neg := x.neg
@@ -126,7 +119,6 @@ func (z *Int) Sub(x, y *Int) *Int {
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
@@ -138,7 +130,6 @@ func (z *Int) Mul(x, y *Int) *Int {
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.
@@ -162,7 +153,6 @@ func (z *Int) MulRange(a, b int64) *Int {
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
@@ -171,7 +161,6 @@ func (z *Int) Binomial(n, k int64) *Int {
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.
@@ -181,7 +170,6 @@ func (z *Int) Quo(x, y *Int) *Int {
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.
@@ -191,7 +179,6 @@ func (z *Int) Rem(x, y *Int) *Int {
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.
@@ -209,7 +196,6 @@ func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
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.
@@ -227,7 +213,6 @@ func (z *Int) Div(x, y *Int) *Int {
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.
@@ -248,7 +233,6 @@ func (z *Int) Mod(x, y *Int) *Int {
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.
@@ -281,7 +265,6 @@ func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
return z, m
}
-
// Cmp compares x and y and returns:
//
// -1 if x < y
@@ -307,49 +290,197 @@ func (x *Int) Cmp(y *Int) (r int) {
return
}
-
func (x *Int) String() string {
- s := ""
- if x.neg {
- s = "-"
+ switch {
+ case x == nil:
+ return "<nil>"
+ case x.neg:
+ return "-" + x.abs.decimalString()
}
- return s + x.abs.string(10)
+ return x.abs.decimalString()
}
-
-func fmtbase(ch int) int {
+func charset(ch int) string {
switch ch {
case 'b':
- return 2
+ return lowercaseDigits[0:2]
case 'o':
- return 8
- case 'd':
- return 10
+ return lowercaseDigits[0:8]
+ case 'd', 's', 'v':
+ return lowercaseDigits[0:10]
case 'x':
- return 16
+ return lowercaseDigits[0:16]
+ case 'X':
+ return uppercaseDigits[0:16]
}
- return 10
+ return "" // unknown format
}
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+ if len(text) > 0 {
+ b := []byte(text)
+ for ; count > 0; count-- {
+ s.Write(b)
+ }
+ }
+}
// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), 'd' (decimal) and
-// 'x' (hexadecimal).
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
+// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
//
func (x *Int) Format(s fmt.State, ch int) {
- if x == nil {
+ cs := charset(ch)
+
+ // special cases
+ switch {
+ case cs == "":
+ // unknown format
+ fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
+ return
+ case x == nil:
fmt.Fprint(s, "<nil>")
return
}
- if x.neg {
- fmt.Fprint(s, "-")
+
+ // determine sign character
+ sign := ""
+ switch {
+ case x.neg:
+ sign = "-"
+ case s.Flag('+'): // supersedes ' ' when both specified
+ sign = "+"
+ case s.Flag(' '):
+ sign = " "
+ }
+
+ // determine prefix characters for indicating output base
+ prefix := ""
+ if s.Flag('#') {
+ switch ch {
+ case 'o': // octal
+ prefix = "0"
+ case 'x': // hexadecimal
+ prefix = "0x"
+ case 'X':
+ prefix = "0X"
+ }
+ }
+
+ // determine digits with base set by len(cs) and digit characters from cs
+ digits := x.abs.string(cs)
+
+ // number of characters for the three classes of number padding
+ var left int // space characters to left of digits for right justification ("%8d")
+ var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+ var right int // space characters to right of digits for left justification ("%-8d")
+
+ // determine number padding from precision: the least number of digits to output
+ precision, precisionSet := s.Precision()
+ if precisionSet {
+ switch {
+ case len(digits) < precision:
+ zeroes = precision - len(digits) // count of zero padding
+ case digits == "0" && precision == 0:
+ return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+ }
+ }
+
+ // determine field pad from width: the least number of characters to output
+ length := len(sign) + len(prefix) + zeroes + len(digits)
+ if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+ switch d := width - length; {
+ case s.Flag('-'):
+ // pad on the right with spaces; supersedes '0' when both specified
+ right = d
+ case s.Flag('0') && !precisionSet:
+ // pad with zeroes unless precision also specified
+ zeroes = d
+ default:
+ // pad on the left with spaces
+ left = d
+ }
}
- fmt.Fprint(s, x.abs.string(fmtbase(ch)))
+
+ // print number as [left pad][sign][prefix][zero pad][digits][right pad]
+ writeMultiple(s, " ", left)
+ writeMultiple(s, sign, 1)
+ writeMultiple(s, prefix, 1)
+ writeMultiple(s, "0", zeroes)
+ writeMultiple(s, digits, 1)
+ writeMultiple(s, " ", right)
}
+// scan sets z to the integer value corresponding to the longest possible prefix
+// read from r representing a signed integer number in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined. The syntax follows the syntax of
+// integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// 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) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
+ // determine sign
+ ch, _, err := r.ReadRune()
+ if err != nil {
+ return z, 0, err
+ }
+ neg := false
+ switch ch {
+ case '-':
+ neg = true
+ case '+': // nothing to do
+ default:
+ r.UnreadRune()
+ }
-// Int64 returns the int64 representation of z.
-// If z cannot be represented in an int64, the result is undefined.
+ // determine mantissa
+ z.abs, base, err = z.abs.scan(r, base)
+ if err != nil {
+ return z, base, err
+ }
+ z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+ return z, base, nil
+}
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
+// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+func (z *Int) Scan(s fmt.ScanState, ch int) os.Error {
+ s.SkipSpace() // skip leading space characters
+ base := 0
+ switch ch {
+ case 'b':
+ base = 2
+ case 'o':
+ base = 8
+ case 'd':
+ base = 10
+ case 'x', 'X':
+ base = 16
+ case 's', 'v':
+ // let scan determine the base
+ default:
+ return os.NewError("Int.Scan: invalid verb")
+ }
+ _, _, err := z.scan(s, base)
+ return err
+}
+
+// Int64 returns the int64 representation of x.
+// If x cannot be represented in an int64, the result is undefined.
func (x *Int) Int64() int64 {
if len(x.abs) == 0 {
return 0
@@ -364,40 +495,25 @@ func (x *Int) Int64() int64 {
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.
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// 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) {
+ r := strings.NewReader(s)
+ _, _, err := z.scan(r, base)
+ if err != nil {
return z, false
}
- z.neg = len(z.abs) > 0 && neg // 0 has no sign
-
- return z, true
+ _, _, err = r.ReadRune()
+ return z, err == os.EOF // err == os.EOF => scan consumed all of s
}
-
// SetBytes interprets buf as the bytes of a big-endian unsigned
// integer, sets z to that value, and returns z.
func (z *Int) SetBytes(buf []byte) *Int {
@@ -406,21 +522,18 @@ func (z *Int) SetBytes(buf []byte) *Int {
return z
}
-
// Bytes returns the absolute value of z as a big-endian byte slice.
func (z *Int) Bytes() []byte {
buf := make([]byte, len(z.abs)*_S)
return buf[z.abs.bytes(buf):]
}
-
// 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 {
@@ -441,7 +554,6 @@ func (z *Int) Exp(x, y, m *Int) *Int {
return z
}
-
// GcdInt sets d to the greatest common divisor of a and b, which must be
// positive numbers.
// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.
@@ -500,7 +612,6 @@ func GcdInt(d, x, y, a, b *Int) {
*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.
@@ -508,8 +619,7 @@ 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.
+// 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 {
@@ -520,7 +630,6 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
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 {
@@ -534,7 +643,6 @@ func (z *Int) ModInverse(g, p *Int) *Int {
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)
@@ -542,7 +650,6 @@ func (z *Int) Lsh(x *Int, n uint) *Int {
return z
}
-
// Rsh sets z = x >> n and returns z.
func (z *Int) Rsh(x *Int, n uint) *Int {
if x.neg {
@@ -559,6 +666,39 @@ func (z *Int) Rsh(x *Int, n uint) *Int {
return z
}
+// Bit returns the value of the i'th bit of z. That is, it
+// returns (z>>i)&1. The bit index i must be >= 0.
+func (z *Int) Bit(i int) uint {
+ if i < 0 {
+ panic("negative bit index")
+ }
+ if z.neg {
+ t := nat{}.sub(z.abs, natOne)
+ return t.bit(uint(i)) ^ 1
+ }
+
+ return z.abs.bit(uint(i))
+}
+
+// SetBit sets the i'th bit of z to bit and returns z.
+// That is, if bit is 1 SetBit sets z = x | (1 << i);
+// if bit is 0 it sets z = x &^ (1 << i). If bit is not 0 or 1,
+// SetBit will panic.
+func (z *Int) SetBit(x *Int, i int, b uint) *Int {
+ if i < 0 {
+ panic("negative bit index")
+ }
+ if x.neg {
+ t := z.abs.sub(x.abs, natOne)
+ t = t.setBit(t, uint(i), b^1)
+ z.abs = t.add(t, natOne)
+ z.neg = len(z.abs) > 0
+ return z
+ }
+ z.abs = z.abs.setBit(x.abs, uint(i), b)
+ z.neg = false
+ return z
+}
// And sets z = x & y and returns z.
func (z *Int) And(x, y *Int) *Int {
@@ -590,7 +730,6 @@ func (z *Int) And(x, y *Int) *Int {
return z
}
-
// AndNot sets z = x &^ y and returns z.
func (z *Int) AndNot(x, y *Int) *Int {
if x.neg == y.neg {
@@ -624,7 +763,6 @@ func (z *Int) AndNot(x, y *Int) *Int {
return z
}
-
// Or sets z = x | y and returns z.
func (z *Int) Or(x, y *Int) *Int {
if x.neg == y.neg {
@@ -655,7 +793,6 @@ func (z *Int) Or(x, y *Int) *Int {
return z
}
-
// Xor sets z = x ^ y and returns z.
func (z *Int) Xor(x, y *Int) *Int {
if x.neg == y.neg {
@@ -686,7 +823,6 @@ func (z *Int) Xor(x, y *Int) *Int {
return z
}
-
// Not sets z = ^x and returns z.
func (z *Int) Not(x *Int) *Int {
if x.neg {
@@ -702,15 +838,14 @@ func (z *Int) Not(x *Int) *Int {
return z
}
-
// Gob codec version. Permits backward-compatible changes to the encoding.
-const version byte = 1
+const intGobVersion byte = 1
// GobEncode implements the gob.GobEncoder interface.
func (z *Int) GobEncode() ([]byte, os.Error) {
- buf := make([]byte, len(z.abs)*_S+1) // extra byte for version and sign bit
+ buf := make([]byte, 1+len(z.abs)*_S) // extra byte for version and sign bit
i := z.abs.bytes(buf) - 1 // i >= 0
- b := version << 1 // make space for sign bit
+ b := intGobVersion << 1 // make space for sign bit
if z.neg {
b |= 1
}
@@ -718,14 +853,13 @@ func (z *Int) GobEncode() ([]byte, os.Error) {
return buf[i:], nil
}
-
// GobDecode implements the gob.GobDecoder interface.
func (z *Int) GobDecode(buf []byte) os.Error {
if len(buf) == 0 {
return os.NewError("Int.GobDecode: no data")
}
b := buf[0]
- if b>>1 != version {
+ if b>>1 != intGobVersion {
return os.NewError(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
}
z.neg = b&1 != 0
diff --git a/libgo/go/big/int_test.go b/libgo/go/big/int_test.go
index 9c19dd5da6d..03446d6ae2d 100644
--- a/libgo/go/big/int_test.go
+++ b/libgo/go/big/int_test.go
@@ -13,7 +13,6 @@ import (
"testing/quick"
)
-
func isNormalized(x *Int) bool {
if len(x.abs) == 0 {
return !x.neg
@@ -22,13 +21,11 @@ func isNormalized(x *Int) bool {
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)},
@@ -38,7 +35,6 @@ var sumZZ = []argZZ{
{NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
}
-
var prodZZ = []argZZ{
{NewInt(0), NewInt(0), NewInt(0)},
{NewInt(0), NewInt(1), NewInt(0)},
@@ -47,7 +43,6 @@ var prodZZ = []argZZ{
// TODO(gri) add larger products
}
-
func TestSignZ(t *testing.T) {
var zero Int
for _, a := range sumZZ {
@@ -59,7 +54,6 @@ func TestSignZ(t *testing.T) {
}
}
-
func TestSetZ(t *testing.T) {
for _, a := range sumZZ {
var z Int
@@ -73,7 +67,6 @@ func TestSetZ(t *testing.T) {
}
}
-
func TestAbsZ(t *testing.T) {
var zero Int
for _, a := range sumZZ {
@@ -90,7 +83,6 @@ func TestAbsZ(t *testing.T) {
}
}
-
func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
var z Int
f(&z, a.x, a.y)
@@ -102,7 +94,6 @@ func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
}
}
-
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) }
@@ -121,7 +112,6 @@ func TestSumZZ(t *testing.T) {
}
}
-
func TestProdZZ(t *testing.T) {
MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) }
for _, a := range prodZZ {
@@ -133,7 +123,6 @@ func TestProdZZ(t *testing.T) {
}
}
-
// 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).
@@ -166,7 +155,6 @@ func mulBytes(x, y []byte) []byte {
return z[i:]
}
-
func checkMul(a, b []byte) bool {
var x, y, z1 Int
x.SetBytes(a)
@@ -179,14 +167,12 @@ func checkMul(a, b []byte) bool {
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
@@ -212,7 +198,6 @@ var mulRangesZ = []struct {
},
}
-
func TestMulRangeZ(t *testing.T) {
var tmp Int
// test entirely positive ranges
@@ -231,7 +216,6 @@ func TestMulRangeZ(t *testing.T) {
}
}
-
var stringTests = []struct {
in string
out string
@@ -280,7 +264,6 @@ var stringTests = []struct {
{"1001010111", "1001010111", 2, 0x257, true},
}
-
func format(base int) string {
switch base {
case 2:
@@ -293,7 +276,6 @@ func format(base int) string {
return "%d"
}
-
func TestGetString(t *testing.T) {
z := new(Int)
for i, test := range stringTests {
@@ -316,7 +298,6 @@ func TestGetString(t *testing.T) {
}
}
-
func TestSetString(t *testing.T) {
tmp := new(Int)
for i, test := range stringTests {
@@ -347,6 +328,212 @@ func TestSetString(t *testing.T) {
}
}
+var formatTests = []struct {
+ input string
+ format string
+ output string
+}{
+ {"<nil>", "%x", "<nil>"},
+ {"<nil>", "%#x", "<nil>"},
+ {"<nil>", "%#y", "%!y(big.Int=<nil>)"},
+
+ {"10", "%b", "1010"},
+ {"10", "%o", "12"},
+ {"10", "%d", "10"},
+ {"10", "%v", "10"},
+ {"10", "%x", "a"},
+ {"10", "%X", "A"},
+ {"-10", "%X", "-A"},
+ {"10", "%y", "%!y(big.Int=10)"},
+ {"-10", "%y", "%!y(big.Int=-10)"},
+
+ {"10", "%#b", "1010"},
+ {"10", "%#o", "012"},
+ {"10", "%#d", "10"},
+ {"10", "%#v", "10"},
+ {"10", "%#x", "0xa"},
+ {"10", "%#X", "0XA"},
+ {"-10", "%#X", "-0XA"},
+ {"10", "%#y", "%!y(big.Int=10)"},
+ {"-10", "%#y", "%!y(big.Int=-10)"},
+
+ {"1234", "%d", "1234"},
+ {"1234", "%3d", "1234"},
+ {"1234", "%4d", "1234"},
+ {"-1234", "%d", "-1234"},
+ {"1234", "% 5d", " 1234"},
+ {"1234", "%+5d", "+1234"},
+ {"1234", "%-5d", "1234 "},
+ {"1234", "%x", "4d2"},
+ {"1234", "%X", "4D2"},
+ {"-1234", "%3x", "-4d2"},
+ {"-1234", "%4x", "-4d2"},
+ {"-1234", "%5x", " -4d2"},
+ {"-1234", "%-5x", "-4d2 "},
+ {"1234", "%03d", "1234"},
+ {"1234", "%04d", "1234"},
+ {"1234", "%05d", "01234"},
+ {"1234", "%06d", "001234"},
+ {"-1234", "%06d", "-01234"},
+ {"1234", "%+06d", "+01234"},
+ {"1234", "% 06d", " 01234"},
+ {"1234", "%-6d", "1234 "},
+ {"1234", "%-06d", "1234 "},
+ {"-1234", "%-06d", "-1234 "},
+
+ {"1234", "%.3d", "1234"},
+ {"1234", "%.4d", "1234"},
+ {"1234", "%.5d", "01234"},
+ {"1234", "%.6d", "001234"},
+ {"-1234", "%.3d", "-1234"},
+ {"-1234", "%.4d", "-1234"},
+ {"-1234", "%.5d", "-01234"},
+ {"-1234", "%.6d", "-001234"},
+
+ {"1234", "%8.3d", " 1234"},
+ {"1234", "%8.4d", " 1234"},
+ {"1234", "%8.5d", " 01234"},
+ {"1234", "%8.6d", " 001234"},
+ {"-1234", "%8.3d", " -1234"},
+ {"-1234", "%8.4d", " -1234"},
+ {"-1234", "%8.5d", " -01234"},
+ {"-1234", "%8.6d", " -001234"},
+
+ {"1234", "%+8.3d", " +1234"},
+ {"1234", "%+8.4d", " +1234"},
+ {"1234", "%+8.5d", " +01234"},
+ {"1234", "%+8.6d", " +001234"},
+ {"-1234", "%+8.3d", " -1234"},
+ {"-1234", "%+8.4d", " -1234"},
+ {"-1234", "%+8.5d", " -01234"},
+ {"-1234", "%+8.6d", " -001234"},
+
+ {"1234", "% 8.3d", " 1234"},
+ {"1234", "% 8.4d", " 1234"},
+ {"1234", "% 8.5d", " 01234"},
+ {"1234", "% 8.6d", " 001234"},
+ {"-1234", "% 8.3d", " -1234"},
+ {"-1234", "% 8.4d", " -1234"},
+ {"-1234", "% 8.5d", " -01234"},
+ {"-1234", "% 8.6d", " -001234"},
+
+ {"1234", "%.3x", "4d2"},
+ {"1234", "%.4x", "04d2"},
+ {"1234", "%.5x", "004d2"},
+ {"1234", "%.6x", "0004d2"},
+ {"-1234", "%.3x", "-4d2"},
+ {"-1234", "%.4x", "-04d2"},
+ {"-1234", "%.5x", "-004d2"},
+ {"-1234", "%.6x", "-0004d2"},
+
+ {"1234", "%8.3x", " 4d2"},
+ {"1234", "%8.4x", " 04d2"},
+ {"1234", "%8.5x", " 004d2"},
+ {"1234", "%8.6x", " 0004d2"},
+ {"-1234", "%8.3x", " -4d2"},
+ {"-1234", "%8.4x", " -04d2"},
+ {"-1234", "%8.5x", " -004d2"},
+ {"-1234", "%8.6x", " -0004d2"},
+
+ {"1234", "%+8.3x", " +4d2"},
+ {"1234", "%+8.4x", " +04d2"},
+ {"1234", "%+8.5x", " +004d2"},
+ {"1234", "%+8.6x", " +0004d2"},
+ {"-1234", "%+8.3x", " -4d2"},
+ {"-1234", "%+8.4x", " -04d2"},
+ {"-1234", "%+8.5x", " -004d2"},
+ {"-1234", "%+8.6x", " -0004d2"},
+
+ {"1234", "% 8.3x", " 4d2"},
+ {"1234", "% 8.4x", " 04d2"},
+ {"1234", "% 8.5x", " 004d2"},
+ {"1234", "% 8.6x", " 0004d2"},
+ {"1234", "% 8.7x", " 00004d2"},
+ {"1234", "% 8.8x", " 000004d2"},
+ {"-1234", "% 8.3x", " -4d2"},
+ {"-1234", "% 8.4x", " -04d2"},
+ {"-1234", "% 8.5x", " -004d2"},
+ {"-1234", "% 8.6x", " -0004d2"},
+ {"-1234", "% 8.7x", "-00004d2"},
+ {"-1234", "% 8.8x", "-000004d2"},
+
+ {"1234", "%-8.3d", "1234 "},
+ {"1234", "%-8.4d", "1234 "},
+ {"1234", "%-8.5d", "01234 "},
+ {"1234", "%-8.6d", "001234 "},
+ {"1234", "%-8.7d", "0001234 "},
+ {"1234", "%-8.8d", "00001234"},
+ {"-1234", "%-8.3d", "-1234 "},
+ {"-1234", "%-8.4d", "-1234 "},
+ {"-1234", "%-8.5d", "-01234 "},
+ {"-1234", "%-8.6d", "-001234 "},
+ {"-1234", "%-8.7d", "-0001234"},
+ {"-1234", "%-8.8d", "-00001234"},
+
+ {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+ {"0", "%.d", ""},
+ {"0", "%.0d", ""},
+ {"0", "%3.d", ""},
+}
+
+func TestFormat(t *testing.T) {
+ for i, test := range formatTests {
+ var x *Int
+ if test.input != "<nil>" {
+ var ok bool
+ x, ok = new(Int).SetString(test.input, 0)
+ if !ok {
+ t.Errorf("#%d failed reading input %s", i, test.input)
+ }
+ }
+ output := fmt.Sprintf(test.format, x)
+ if output != test.output {
+ t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
+ }
+ }
+}
+
+var scanTests = []struct {
+ input string
+ format string
+ output string
+ remaining int
+}{
+ {"1010", "%b", "10", 0},
+ {"0b1010", "%v", "10", 0},
+ {"12", "%o", "10", 0},
+ {"012", "%v", "10", 0},
+ {"10", "%d", "10", 0},
+ {"10", "%v", "10", 0},
+ {"a", "%x", "10", 0},
+ {"0xa", "%v", "10", 0},
+ {"A", "%X", "10", 0},
+ {"-A", "%X", "-10", 0},
+ {"+0b1011001", "%v", "89", 0},
+ {"0xA", "%v", "10", 0},
+ {"0 ", "%v", "0", 1},
+ {"2+3", "%v", "2", 2},
+ {"0XABC 12", "%v", "2748", 3},
+}
+
+func TestScan(t *testing.T) {
+ var buf bytes.Buffer
+ for i, test := range scanTests {
+ x := new(Int)
+ buf.Reset()
+ buf.WriteString(test.input)
+ if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
+ t.Errorf("#%d error: %s", i, err.String())
+ }
+ if x.String() != test.output {
+ t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+ }
+ if buf.Len() != test.remaining {
+ t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+ }
+ }
+}
// Examples from the Go Language Spec, section "Arithmetic operators"
var divisionSignsTests = []struct {
@@ -362,7 +549,6 @@ var divisionSignsTests = []struct {
{8, 4, 2, 0, 2, 0},
}
-
func TestDivisionSigns(t *testing.T) {
for i, test := range divisionSignsTests {
x := NewInt(test.x)
@@ -420,7 +606,6 @@ func TestDivisionSigns(t *testing.T) {
}
}
-
func checkSetBytes(b []byte) bool {
hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
hex2 := hex.EncodeToString(b)
@@ -436,27 +621,23 @@ func checkSetBytes(b []byte) bool {
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)
@@ -479,7 +660,6 @@ func checkQuo(x, y []byte) bool {
return uprime.Cmp(u) == 0
}
-
var quoTests = []struct {
x, y string
q, r string
@@ -498,7 +678,6 @@ var quoTests = []struct {
},
}
-
func TestQuo(t *testing.T) {
if err := quick.Check(checkQuo, nil); err != nil {
t.Error(err)
@@ -519,7 +698,6 @@ func TestQuo(t *testing.T) {
}
}
-
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.
@@ -539,7 +717,6 @@ func TestQuoStepD6(t *testing.T) {
}
}
-
var bitLenTests = []struct {
in string
out int
@@ -558,7 +735,6 @@ var bitLenTests = []struct {
{"-0x4000000000000000000000", 87},
}
-
func TestBitLen(t *testing.T) {
for i, test := range bitLenTests {
x, ok := new(Int).SetString(test.in, 0)
@@ -573,7 +749,6 @@ func TestBitLen(t *testing.T) {
}
}
-
var expTests = []struct {
x, y, m string
out string
@@ -598,7 +773,6 @@ var expTests = []struct {
},
}
-
func TestExp(t *testing.T) {
for i, test := range expTests {
x, ok1 := new(Int).SetString(test.x, 0)
@@ -629,7 +803,6 @@ func TestExp(t *testing.T) {
}
}
-
func checkGcd(aBytes, bBytes []byte) bool {
a := new(Int).SetBytes(aBytes)
b := new(Int).SetBytes(bBytes)
@@ -646,7 +819,6 @@ func checkGcd(aBytes, bBytes []byte) bool {
return x.Cmp(d) == 0
}
-
var gcdTests = []struct {
a, b int64
d, x, y int64
@@ -654,7 +826,6 @@ var gcdTests = []struct {
{120, 23, 1, -9, 47},
}
-
func TestGcd(t *testing.T) {
for i, test := range gcdTests {
a := NewInt(test.a)
@@ -680,7 +851,6 @@ func TestGcd(t *testing.T) {
quick.Check(checkGcd, nil)
}
-
var primes = []string{
"2",
"3",
@@ -706,7 +876,6 @@ var primes = []string{
"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
}
-
var composites = []string{
"21284175091214687912771199898307297748211672914763848041968395774954376176754",
"6084766654921918907427900243509372380954290099172559290432744450051395395951",
@@ -714,7 +883,6 @@ var composites = []string{
"82793403787388584738507275144194252681",
}
-
func TestProbablyPrime(t *testing.T) {
nreps := 20
if testing.Short() {
@@ -738,14 +906,12 @@ func TestProbablyPrime(t *testing.T) {
}
}
-
type intShiftTest struct {
in string
shift uint
out string
}
-
var rshTests = []intShiftTest{
{"0", 0, "0"},
{"-0", 0, "0"},
@@ -773,7 +939,6 @@ var rshTests = []intShiftTest{
{"340282366920938463463374607431768211456", 128, "1"},
}
-
func TestRsh(t *testing.T) {
for i, test := range rshTests {
in, _ := new(Int).SetString(test.in, 10)
@@ -789,7 +954,6 @@ func TestRsh(t *testing.T) {
}
}
-
func TestRshSelf(t *testing.T) {
for i, test := range rshTests {
z, _ := new(Int).SetString(test.in, 10)
@@ -805,7 +969,6 @@ func TestRshSelf(t *testing.T) {
}
}
-
var lshTests = []intShiftTest{
{"0", 0, "0"},
{"0", 1, "0"},
@@ -828,7 +991,6 @@ var lshTests = []intShiftTest{
{"1", 128, "340282366920938463463374607431768211456"},
}
-
func TestLsh(t *testing.T) {
for i, test := range lshTests {
in, _ := new(Int).SetString(test.in, 10)
@@ -844,7 +1006,6 @@ func TestLsh(t *testing.T) {
}
}
-
func TestLshSelf(t *testing.T) {
for i, test := range lshTests {
z, _ := new(Int).SetString(test.in, 10)
@@ -860,7 +1021,6 @@ func TestLshSelf(t *testing.T) {
}
}
-
func TestLshRsh(t *testing.T) {
for i, test := range rshTests {
in, _ := new(Int).SetString(test.in, 10)
@@ -888,7 +1048,6 @@ func TestLshRsh(t *testing.T) {
}
}
-
var int64Tests = []int64{
0,
1,
@@ -902,7 +1061,6 @@ var int64Tests = []int64{
-9223372036854775808,
}
-
func TestInt64(t *testing.T) {
for i, testVal := range int64Tests {
in := NewInt(testVal)
@@ -914,7 +1072,6 @@ func TestInt64(t *testing.T) {
}
}
-
var bitwiseTests = []struct {
x, y string
and, or, xor, andNot string
@@ -958,7 +1115,6 @@ var bitwiseTests = []struct {
},
}
-
type bitFun func(z, x, y *Int) *Int
func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
@@ -971,7 +1127,6 @@ func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
}
}
-
func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
self := new(Int)
self.Set(x)
@@ -984,6 +1139,142 @@ func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
}
}
+func altBit(x *Int, i int) uint {
+ z := new(Int).Rsh(x, uint(i))
+ z = z.And(z, NewInt(1))
+ if z.Cmp(new(Int)) != 0 {
+ return 1
+ }
+ return 0
+}
+
+func altSetBit(z *Int, x *Int, i int, b uint) *Int {
+ one := NewInt(1)
+ m := one.Lsh(one, uint(i))
+ switch b {
+ case 1:
+ return z.Or(x, m)
+ case 0:
+ return z.AndNot(x, m)
+ }
+ panic("set bit is not 0 or 1")
+}
+
+func testBitset(t *testing.T, x *Int) {
+ n := x.BitLen()
+ z := new(Int).Set(x)
+ z1 := new(Int).Set(x)
+ for i := 0; i < n+10; i++ {
+ old := z.Bit(i)
+ old1 := altBit(z1, i)
+ if old != old1 {
+ t.Errorf("bitset: inconsistent value for Bit(%s, %d), got %v want %v", z1, i, old, old1)
+ }
+ z := new(Int).SetBit(z, i, 1)
+ z1 := altSetBit(new(Int), z1, i, 1)
+ if z.Bit(i) == 0 {
+ t.Errorf("bitset: bit %d of %s got 0 want 1", i, x)
+ }
+ if z.Cmp(z1) != 0 {
+ t.Errorf("bitset: inconsistent value after SetBit 1, got %s want %s", z, z1)
+ }
+ z.SetBit(z, i, 0)
+ altSetBit(z1, z1, i, 0)
+ if z.Bit(i) != 0 {
+ t.Errorf("bitset: bit %d of %s got 1 want 0", i, x)
+ }
+ if z.Cmp(z1) != 0 {
+ t.Errorf("bitset: inconsistent value after SetBit 0, got %s want %s", z, z1)
+ }
+ altSetBit(z1, z1, i, old)
+ z.SetBit(z, i, old)
+ if z.Cmp(z1) != 0 {
+ t.Errorf("bitset: inconsistent value after SetBit old, got %s want %s", z, z1)
+ }
+ }
+ if z.Cmp(x) != 0 {
+ t.Errorf("bitset: got %s want %s", z, x)
+ }
+}
+
+var bitsetTests = []struct {
+ x string
+ i int
+ b uint
+}{
+ {"0", 0, 0},
+ {"0", 200, 0},
+ {"1", 0, 1},
+ {"1", 1, 0},
+ {"-1", 0, 1},
+ {"-1", 200, 1},
+ {"0x2000000000000000000000000000", 108, 0},
+ {"0x2000000000000000000000000000", 109, 1},
+ {"0x2000000000000000000000000000", 110, 0},
+ {"-0x2000000000000000000000000001", 108, 1},
+ {"-0x2000000000000000000000000001", 109, 0},
+ {"-0x2000000000000000000000000001", 110, 1},
+}
+
+func TestBitSet(t *testing.T) {
+ for _, test := range bitwiseTests {
+ x := new(Int)
+ x.SetString(test.x, 0)
+ testBitset(t, x)
+ x = new(Int)
+ x.SetString(test.y, 0)
+ testBitset(t, x)
+ }
+ for i, test := range bitsetTests {
+ x := new(Int)
+ x.SetString(test.x, 0)
+ b := x.Bit(test.i)
+ if b != test.b {
+
+ t.Errorf("#%d want %v got %v", i, test.b, b)
+ }
+ }
+}
+
+func BenchmarkBitset(b *testing.B) {
+ z := new(Int)
+ z.SetBit(z, 512, 1)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ z.SetBit(z, i&512, 1)
+ }
+}
+
+func BenchmarkBitsetNeg(b *testing.B) {
+ z := NewInt(-1)
+ z.SetBit(z, 512, 0)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ z.SetBit(z, i&512, 0)
+ }
+}
+
+func BenchmarkBitsetOrig(b *testing.B) {
+ z := new(Int)
+ altSetBit(z, z, 512, 1)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ altSetBit(z, z, i&512, 1)
+ }
+}
+
+func BenchmarkBitsetNegOrig(b *testing.B) {
+ z := NewInt(-1)
+ altSetBit(z, z, 512, 0)
+ b.ResetTimer()
+ b.StartTimer()
+ for i := b.N - 1; i >= 0; i-- {
+ altSetBit(z, z, i&512, 0)
+ }
+}
func TestBitwise(t *testing.T) {
x := new(Int)
@@ -1003,7 +1294,6 @@ func TestBitwise(t *testing.T) {
}
}
-
var notTests = []struct {
in string
out string
@@ -1037,7 +1327,6 @@ func TestNot(t *testing.T) {
}
}
-
var modInverseTests = []struct {
element string
prime string
@@ -1062,7 +1351,7 @@ func TestModInverse(t *testing.T) {
}
}
-
+// used by TestIntGobEncoding and TestRatGobEncoding
var gobEncodingTests = []string{
"0",
"1",
@@ -1073,7 +1362,7 @@ var gobEncodingTests = []string{
"298472983472983471903246121093472394872319615612417471234712061",
}
-func TestGobEncoding(t *testing.T) {
+func TestIntGobEncoding(t *testing.T) {
var medium bytes.Buffer
enc := gob.NewEncoder(&medium)
dec := gob.NewDecoder(&medium)
@@ -1081,7 +1370,8 @@ func TestGobEncoding(t *testing.T) {
for j := 0; j < 2; j++ {
medium.Reset() // empty buffer for each test case (in case of failures)
stest := test
- if j == 0 {
+ if j != 0 {
+ // negative numbers
stest = "-" + test
}
var tx Int
diff --git a/libgo/go/big/nat.go b/libgo/go/big/nat.go
index 4848d427b39..be3aff29d18 100644
--- a/libgo/go/big/nat.go
+++ b/libgo/go/big/nat.go
@@ -18,7 +18,11 @@ package big
// These are the building blocks for the operations on signed integers
// and rationals.
-import "rand"
+import (
+ "io"
+ "os"
+ "rand"
+)
// An unsigned integer x of the form
//
@@ -40,14 +44,12 @@ var (
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 {
@@ -56,7 +58,6 @@ func (z nat) norm() nat {
return z[0:i]
}
-
func (z nat) make(n int) nat {
if n <= cap(z) {
return z[0:n] // reuse z
@@ -67,7 +68,6 @@ func (z nat) make(n int) nat {
return make(nat, n, n+e)
}
-
func (z nat) setWord(x Word) nat {
if x == 0 {
return z.make(0)
@@ -77,7 +77,6 @@ func (z nat) setWord(x Word) nat {
return z
}
-
func (z nat) setUint64(x uint64) nat {
// single-digit values
if w := Word(x); uint64(w) == x {
@@ -100,14 +99,12 @@ func (z nat) setUint64(x uint64) nat {
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)
@@ -134,7 +131,6 @@ func (z nat) add(x, y nat) nat {
return z.norm()
}
-
func (z nat) sub(x, y nat) nat {
m := len(x)
n := len(y)
@@ -163,7 +159,6 @@ func (z nat) sub(x, y nat) nat {
return z.norm()
}
-
func (x nat) cmp(y nat) (r int) {
m := len(x)
n := len(y)
@@ -191,7 +186,6 @@ func (x nat) cmp(y nat) (r int) {
return
}
-
func (z nat) mulAddWW(x nat, y, r Word) nat {
m := len(x)
if m == 0 || y == 0 {
@@ -205,7 +199,6 @@ func (z nat) mulAddWW(x nat, y, r Word) nat {
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) {
@@ -217,7 +210,6 @@ func basicMul(z, x, y nat) {
}
}
-
// 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) {
@@ -226,7 +218,6 @@ func karatsubaAdd(z, x nat, n int) {
}
}
-
// Like karatsubaAdd, but does subtract.
func karatsubaSub(z, x nat, n int) {
if c := subVV(z[0:n], z, x); c != 0 {
@@ -234,7 +225,6 @@ func karatsubaSub(z, x nat, n int) {
}
}
-
// Operands that are shorter than karatsubaThreshold are multiplied using
// "grade school" multiplication; for longer operands the Karatsuba algorithm
// is used.
@@ -339,13 +329,11 @@ func karatsuba(z, x, y nat) {
}
}
-
// 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)
@@ -360,7 +348,6 @@ func addAt(z, x nat, i int) {
}
}
-
func max(x, y int) int {
if x > y {
return x
@@ -368,7 +355,6 @@ func max(x, y int) int {
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
@@ -382,7 +368,6 @@ func karatsubaLen(n int) int {
return n << i
}
-
func (z nat) mul(x, y nat) nat {
m := len(x)
n := len(y)
@@ -450,7 +435,6 @@ func (z nat) mul(x, y nat) nat {
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 {
@@ -469,7 +453,6 @@ func (z nat) mulRange(a, b uint64) nat {
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)
@@ -490,7 +473,6 @@ func (z nat) divW(x nat, y Word) (q nat, r Word) {
return
}
-
func (z nat) div(z2, u, v nat) (q, r nat) {
if len(v) == 0 {
panic("division by zero")
@@ -518,7 +500,6 @@ func (z nat) div(z2, u, v nat) (q, r nat) {
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.
@@ -545,9 +526,14 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
u.clear()
// D1.
- shift := Word(leadingZeros(v[n-1]))
- shlVW(v, v, shift)
- u[len(uIn)] = shlVW(u[0:len(uIn)], uIn, shift)
+ shift := leadingZeros(v[n-1])
+ if shift > 0 {
+ // do not modify v, it may be used by another goroutine simultaneously
+ v1 := make(nat, n)
+ shlVU(v1, v, shift)
+ v = v1
+ }
+ u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
// D2.
for j := m; j >= 0; j-- {
@@ -586,14 +572,12 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
}
q = q.norm()
- shrVW(u, u, shift)
- shrVW(v, v, shift)
+ shrVU(u, u, 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 {
@@ -602,103 +586,253 @@ func (x nat) bitLen() int {
return 0
}
+// MaxBase is the largest number base accepted for string conversions.
+const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
-func hexValue(ch byte) int {
- var d byte
+
+func hexValue(ch int) Word {
+ d := MaxBase + 1 // illegal base
switch {
case '0' <= ch && ch <= '9':
d = ch - '0'
- case 'a' <= ch && ch <= 'f':
+ case 'a' <= ch && ch <= 'z':
d = ch - 'a' + 10
- case 'A' <= ch && ch <= 'F':
+ case 'A' <= ch && ch <= 'Z':
d = ch - 'A' + 10
- default:
- return -1
}
- return int(d)
+ return Word(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.
+// scan sets z to the natural number corresponding to the longest possible prefix
+// read from r representing an unsigned integer in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined. The syntax 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.
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// 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) {
+func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) {
+ // reject illegal bases
+ if base < 0 || base == 1 || MaxBase < base {
+ return z, 0, os.NewError("illegal number base")
+ }
+
+ // one char look-ahead
+ ch, _, err := r.ReadRune()
+ if err != nil {
+ return z, 0, err
+ }
+
// determine base if necessary
- i, n := 0, len(s)
+ b := Word(base)
if base == 0 {
- base = 10
- if n > 0 && s[0] == '0' {
- base, i = 8, 1
- if n > 1 {
- switch s[1] {
+ b = 10
+ if ch == '0' {
+ switch ch, _, err = r.ReadRune(); err {
+ case nil:
+ b = 8
+ switch ch {
case 'x', 'X':
- base, i = 16, 2
+ b = 16
case 'b', 'B':
- base, i = 2, 2
+ b = 2
}
+ if b == 2 || b == 16 {
+ if ch, _, err = r.ReadRune(); err != nil {
+ return z, 0, err
+ }
+ }
+ case os.EOF:
+ return z, 10, nil
+ default:
+ return z, 10, err
}
}
}
- // reject illegal bases or strings consisting only of prefix
- if base < 2 || 16 < base || (base != 8 && i >= n) {
- return z, 0, 0
- }
-
// convert string
+ // - group as many digits d as possible together into a "super-digit" dd with "super-base" bb
+ // - only when bb does not fit into a word anymore, do a full number mulAddWW using bb and dd
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))
+ bb := Word(1)
+ dd := Word(0)
+ for max := _M / b; ; {
+ d := hexValue(ch)
+ if d >= b {
+ r.UnreadRune() // ch does not belong to number anymore
+ break
+ }
+
+ if bb <= max {
+ bb *= b
+ dd = dd*b + d
} else {
+ // bb * b would overflow
+ z = z.mulAddWW(z, bb, dd)
+ bb = b
+ dd = d
+ }
+
+ if ch, _, err = r.ReadRune(); err != nil {
+ if err != os.EOF {
+ return z, int(b), err
+ }
break
}
}
- return z.norm(), base, i
+ switch {
+ case bb > 1:
+ // there was at least one mantissa digit
+ z = z.mulAddWW(z, bb, dd)
+ case base == 0 && b == 8:
+ // there was only the octal prefix 0 (possibly followed by digits > 7);
+ // return base 10, not 8
+ return z, 10, nil
+ case base != 0 || b != 8:
+ // there was neither a mantissa digit nor the octal prefix 0
+ return z, int(b), os.NewError("syntax error scanning number")
+ }
+
+ return z.norm(), int(b), nil
}
+// Character sets for string conversion.
+const (
+ lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
+ uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+)
-// 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")
- }
+// decimalString returns a decimal representation of x.
+// It calls x.string with the charset "0123456789".
+func (x nat) decimalString() string {
+ return x.string(lowercaseDigits[0:10])
+}
- if len(x) == 0 {
- return "0"
+// string converts x to a string using digits from a charset; a digit with
+// value d is represented by charset[d]. The conversion base is determined
+// by len(charset), which must be >= 2.
+func (x nat) string(charset string) string {
+ b := Word(len(charset))
+
+ // special cases
+ switch {
+ case b < 2 || b > 256:
+ panic("illegal base")
+ case len(x) == 0:
+ return string(charset[0])
}
// allocate buffer for conversion
- i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+ i := x.bitLen()/log2(b) + 1 // +1: round up
s := make([]byte, i)
- // don't destroy x
+ // special case: power of two bases can avoid divisions completely
+ if b == b&-b {
+ // shift is base-b digit size in bits
+ shift := uint(trailingZeroBits(b)) // shift > 0 because b >= 2
+ mask := Word(1)<<shift - 1
+ w := x[0]
+ nbits := uint(_W) // number of unprocessed bits in w
+
+ // convert less-significant words
+ for k := 1; k < len(x); k++ {
+ // convert full digits
+ for nbits >= shift {
+ i--
+ s[i] = charset[w&mask]
+ w >>= shift
+ nbits -= shift
+ }
+
+ // convert any partial leading digit and advance to next word
+ if nbits == 0 {
+ // no partial digit remaining, just advance
+ w = x[k]
+ nbits = _W
+ } else {
+ // partial digit in current (k-1) and next (k) word
+ w |= x[k] << nbits
+ i--
+ s[i] = charset[w&mask]
+
+ // advance
+ w = x[k] >> (shift - nbits)
+ nbits = _W - (shift - nbits)
+ }
+ }
+
+ // convert digits of most-significant word (omit leading zeros)
+ for nbits >= 0 && w != 0 {
+ i--
+ s[i] = charset[w&mask]
+ w >>= shift
+ nbits -= shift
+ }
+
+ return string(s[i:])
+ }
+
+ // general case: extract groups of digits by multiprecision division
+
+ // maximize ndigits where b**ndigits < 2^_W; bb (big base) is b**ndigits
+ bb := Word(1)
+ ndigits := 0
+ for max := Word(_M / b); bb <= max; bb *= b {
+ ndigits++
+ }
+
+ // preserve x, create local copy for use in repeated divisions
q := nat(nil).set(x)
+ var r Word
// convert
- for len(q) > 0 {
- i--
- var r Word
- q, r = q.divW(q, Word(base))
- s[i] = "0123456789abcdef"[r]
+ if b == 10 { // hard-coding for 10 here speeds this up by 1.25x
+ for len(q) > 0 {
+ // extract least significant, base bb "digit"
+ q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
+ if len(q) == 0 {
+ // skip leading zeros in most-significant group of digits
+ for j := 0; j < ndigits && r != 0; j++ {
+ i--
+ s[i] = charset[r%10]
+ r /= 10
+ }
+ } else {
+ for j := 0; j < ndigits; j++ {
+ i--
+ s[i] = charset[r%10]
+ r /= 10
+ }
+ }
+ }
+ } else {
+ for len(q) > 0 {
+ // extract least significant group of digits
+ q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
+ if len(q) == 0 {
+ // skip leading zeros in most-significant group of digits
+ for j := 0; j < ndigits && r != 0; j++ {
+ i--
+ s[i] = charset[r%b]
+ r /= b
+ }
+ } else {
+ for j := 0; j < ndigits; j++ {
+ i--
+ s[i] = charset[r%b]
+ r /= b
+ }
+ }
+ }
}
return string(s[i:])
}
-
const deBruijn32 = 0x077CB531
var deBruijn32Lookup = []byte{
@@ -721,7 +855,7 @@ var deBruijn64Lookup = []byte{
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
+ // to the power of k. Multiplying 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
@@ -739,7 +873,6 @@ func trailingZeroBits(x Word) int {
return 0
}
-
// z = x << s
func (z nat) shl(x nat, s uint) nat {
m := len(x)
@@ -750,13 +883,12 @@ func (z nat) shl(x nat, s uint) nat {
n := m + int(s/_W)
z = z.make(n + 1)
- z[n] = shlVW(z[n-m:n], x, Word(s%_W))
+ z[n] = shlVU(z[n-m:n], x, 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)
@@ -767,11 +899,45 @@ func (z nat) shr(x nat, s uint) nat {
// n > 0
z = z.make(n)
- shrVW(z, x[m-n:], Word(s%_W))
+ shrVU(z, x[m-n:], s%_W)
return z.norm()
}
+func (z nat) setBit(x nat, i uint, b uint) nat {
+ j := int(i / _W)
+ m := Word(1) << (i % _W)
+ n := len(x)
+ switch b {
+ case 0:
+ z = z.make(n)
+ copy(z, x)
+ if j >= n {
+ // no need to grow
+ return z
+ }
+ z[j] &^= m
+ return z.norm()
+ case 1:
+ if j >= n {
+ n = j + 1
+ }
+ z = z.make(n)
+ copy(z, x)
+ z[j] |= m
+ // no need to normalize
+ return z
+ }
+ panic("set bit is not 0 or 1")
+}
+
+func (z nat) bit(i uint) uint {
+ j := int(i / _W)
+ if j >= len(z) {
+ return 0
+ }
+ return uint(z[j] >> (i % _W) & 1)
+}
func (z nat) and(x, y nat) nat {
m := len(x)
@@ -789,7 +955,6 @@ func (z nat) and(x, y nat) nat {
return z.norm()
}
-
func (z nat) andNot(x, y nat) nat {
m := len(x)
n := len(y)
@@ -807,7 +972,6 @@ func (z nat) andNot(x, y nat) nat {
return z.norm()
}
-
func (z nat) or(x, y nat) nat {
m := len(x)
n := len(y)
@@ -827,7 +991,6 @@ func (z nat) or(x, y nat) nat {
return z.norm()
}
-
func (z nat) xor(x, y nat) nat {
m := len(x)
n := len(y)
@@ -847,10 +1010,10 @@ func (z nat) xor(x, y nat) nat {
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 }
-
+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) {
@@ -860,30 +1023,29 @@ func (x nat) modW(d Word) (r Word) {
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
+// powersOfTwoDecompose finds q and k with x = q * 1<<k and q is odd, or q and k are 0.
+func (x nat) powersOfTwoDecompose() (q nat, k int) {
+ if len(x) == 0 {
+ return x, 0
}
- zeroWords := 0
- for n[zeroWords] == 0 {
- zeroWords++
+ // One of the words must be non-zero by definition,
+ // so this loop will terminate with i < len(x), and
+ // i is the number of 0 words.
+ i := 0
+ for x[i] == 0 {
+ i++
}
- // One of the words must be non-zero by invariant, therefore
- // zeroWords < len(n).
- x := trailingZeroBits(n[zeroWords])
+ n := trailingZeroBits(x[i]) // x[i] != 0
- q = q.make(len(n) - zeroWords)
- shrVW(q, n[zeroWords:], Word(x))
- q = q.norm()
+ q = make(nat, len(x)-i)
+ shrVU(q, x[i:], uint(n))
- k = Word(_W*zeroWords + x)
+ q = q.norm()
+ k = i*_W + n
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 {
@@ -914,7 +1076,6 @@ func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
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 {
@@ -983,7 +1144,6 @@ func (z nat) expNN(x, y, m nat) nat {
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.
@@ -1050,7 +1210,7 @@ NextRandom:
if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
continue
}
- for j := Word(1); j < k; j++ {
+ for j := 1; j < k; j++ {
y = y.mul(y, y)
quotient, y = quotient.div(y, y, n)
if y.cmp(nm1) == 0 {
@@ -1066,7 +1226,6 @@ NextRandom:
return true
}
-
// bytes writes the value of z into buf using big-endian encoding.
// len(buf) must be >= len(z)*_S. The value of z is encoded in the
// slice buf[i:]. The number i of unused bytes at the beginning of
@@ -1088,7 +1247,6 @@ func (z nat) bytes(buf []byte) (i int) {
return
}
-
// setBytes interprets buf as the bytes of a big-endian unsigned
// integer, sets z to that value, and returns z.
func (z nat) setBytes(buf []byte) nat {
diff --git a/libgo/go/big/nat_test.go b/libgo/go/big/nat_test.go
index 0bcb945548a..71d0860878c 100644
--- a/libgo/go/big/nat_test.go
+++ b/libgo/go/big/nat_test.go
@@ -4,7 +4,12 @@
package big
-import "testing"
+import (
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+)
var cmpTests = []struct {
x, y nat
@@ -26,7 +31,6 @@ var cmpTests = []struct {
{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)
@@ -36,13 +40,11 @@ func TestCmp(t *testing.T) {
}
}
-
type funNN func(z, x, y nat) nat
type argNN struct {
z, x, y nat
}
-
var sumNN = []argNN{
{},
{nat{1}, nil, nat{1}},
@@ -52,7 +54,6 @@ var sumNN = []argNN{
{nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
}
-
var prodNN = []argNN{
{},
{nil, nil, nil},
@@ -64,7 +65,6 @@ var prodNN = []argNN{
{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)
@@ -74,7 +74,6 @@ func TestSet(t *testing.T) {
}
}
-
func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
z := f(nil, a.x, a.y)
if z.cmp(a.z) != 0 {
@@ -82,7 +81,6 @@ func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
}
}
-
func TestFunNN(t *testing.T) {
for _, a := range sumNN {
arg := a
@@ -107,7 +105,6 @@ func TestFunNN(t *testing.T) {
}
}
-
var mulRangesN = []struct {
a, b uint64
prod string
@@ -130,17 +127,15 @@ var mulRangesN = []struct {
},
}
-
func TestMulRangeN(t *testing.T) {
for i, r := range mulRangesN {
- prod := nat(nil).mulRange(r.a, r.b).string(10)
+ prod := nat(nil).mulRange(r.a, r.b).decimalString()
if prod != r.prod {
t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
}
}
}
-
var mulArg, mulTmp nat
func init() {
@@ -151,7 +146,6 @@ func init() {
}
}
-
func benchmarkMulLoad() {
for j := 1; j <= 10; j++ {
x := mulArg[0 : j*100]
@@ -159,46 +153,376 @@ func benchmarkMulLoad() {
}
}
-
func BenchmarkMul(b *testing.B) {
for i := 0; i < b.N; i++ {
benchmarkMulLoad()
}
}
+func toString(x nat, charset string) string {
+ base := len(charset)
-var tab = []struct {
- x nat
- b int
- s string
-}{
- {nil, 10, "0"},
- {nat{1}, 10, "1"},
- {nat{10}, 10, "10"},
- {nat{1234567890}, 10, "1234567890"},
+ // special cases
+ switch {
+ case base < 2:
+ panic("illegal base")
+ case len(x) == 0:
+ return string(charset[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] = charset[r]
+ }
+
+ return string(s[i:])
}
+var strTests = []struct {
+ x nat // nat value to be converted
+ c string // conversion charset
+ s string // expected result
+}{
+ {nil, "01", "0"},
+ {nat{1}, "01", "1"},
+ {nat{0xc5}, "01", "11000101"},
+ {nat{03271}, lowercaseDigits[0:8], "3271"},
+ {nat{10}, lowercaseDigits[0:10], "10"},
+ {nat{1234567890}, uppercaseDigits[0:10], "1234567890"},
+ {nat{0xdeadbeef}, lowercaseDigits[0:16], "deadbeef"},
+ {nat{0xdeadbeef}, uppercaseDigits[0:16], "DEADBEEF"},
+ {nat{0x229be7}, lowercaseDigits[0:17], "1a2b3c"},
+ {nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"},
+}
func TestString(t *testing.T) {
- for _, a := range tab {
- s := a.x.string(a.b)
+ for _, a := range strTests {
+ s := a.x.string(a.c)
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)
+ x, b, err := nat(nil).scan(strings.NewReader(a.s), len(a.c))
+ if x.cmp(a.x) != 0 {
+ t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+ }
+ if b != len(a.c) {
+ t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
+ }
+ if err != nil {
+ t.Errorf("scan%+v\n\tgot error = %s", a, err)
+ }
+ }
+}
+
+var natScanTests = []struct {
+ s string // string to be scanned
+ base int // input base
+ x nat // expected nat
+ b int // expected base
+ ok bool // expected success
+ next int // next character (or 0, if at EOF)
+}{
+ // error: illegal base
+ {base: -1},
+ {base: 1},
+ {base: 37},
+
+ // error: no mantissa
+ {},
+ {s: "?"},
+ {base: 10},
+ {base: 36},
+ {s: "?", base: 10},
+ {s: "0x"},
+ {s: "345", base: 2},
+
+ // no errors
+ {"0", 0, nil, 10, true, 0},
+ {"0", 10, nil, 10, true, 0},
+ {"0", 36, nil, 36, true, 0},
+ {"1", 0, nat{1}, 10, true, 0},
+ {"1", 10, nat{1}, 10, true, 0},
+ {"0 ", 0, nil, 10, true, ' '},
+ {"08", 0, nil, 10, true, '8'},
+ {"018", 0, nat{1}, 8, true, '8'},
+ {"0b1", 0, nat{1}, 2, true, 0},
+ {"0b11000101", 0, nat{0xc5}, 2, true, 0},
+ {"03271", 0, nat{03271}, 8, true, 0},
+ {"10ab", 0, nat{10}, 10, true, 'a'},
+ {"1234567890", 0, nat{1234567890}, 10, true, 0},
+ {"xyz", 36, nat{(33*36+34)*36 + 35}, 36, true, 0},
+ {"xyz?", 36, nat{(33*36+34)*36 + 35}, 36, true, '?'},
+ {"0x", 16, nil, 16, true, 'x'},
+ {"0xdeadbeef", 0, nat{0xdeadbeef}, 16, true, 0},
+ {"0XDEADBEEF", 0, nat{0xdeadbeef}, 16, true, 0},
+}
+
+func TestScanBase(t *testing.T) {
+ for _, a := range natScanTests {
+ r := strings.NewReader(a.s)
+ x, b, err := nat(nil).scan(r, a.base)
+ if err == nil && !a.ok {
+ t.Errorf("scan%+v\n\texpected error", a)
+ }
+ if err != nil {
+ if a.ok {
+ t.Errorf("scan%+v\n\tgot error = %s", a, err)
+ }
+ continue
+ }
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)
+ t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
+ }
+ next, _, err := r.ReadRune()
+ if err == os.EOF {
+ next = 0
+ err = nil
}
- if n != len(a.s) {
- t.Errorf("scan%+v\n\tgot n = %d; want %d", a, n, len(a.s))
+ if err == nil && next != a.next {
+ t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
}
}
}
+var pi = "3" +
+ "14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
+ "32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
+ "28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
+ "96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
+ "31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
+ "60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
+ "22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
+ "29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
+ "81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
+ "21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
+ "55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
+ "63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
+ "75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
+ "45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
+ "34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
+ "16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
+ "04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
+ "26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
+ "99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
+ "53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
+ "68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
+ "13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
+ "88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
+ "79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
+ "68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
+ "21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
+ "06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
+ "14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
+ "21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
+ "05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
+ "23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
+ "90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
+ "31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
+ "20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
+ "97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
+ "44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
+ "44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
+ "85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
+ "58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
+ "27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
+ "09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
+ "79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
+ "06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
+ "91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
+ "94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
+ "78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
+ "24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
+ "59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
+ "34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
+ "88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
+ "94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
+
+// Test case for BenchmarkScanPi.
+func TestScanPi(t *testing.T) {
+ var x nat
+ z, _, err := x.scan(strings.NewReader(pi), 10)
+ if err != nil {
+ t.Errorf("scanning pi: %s", err)
+ }
+ if s := z.decimalString(); s != pi {
+ t.Errorf("scanning pi: got %s", s)
+ }
+}
+
+func BenchmarkScanPi(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ var x nat
+ x.scan(strings.NewReader(pi), 10)
+ }
+}
+
+const (
+ // 314**271
+ // base 2: 2249 digits
+ // base 8: 751 digits
+ // base 10: 678 digits
+ // base 16: 563 digits
+ shortBase = 314
+ shortExponent = 271
+
+ // 3141**2178
+ // base 2: 31577 digits
+ // base 8: 10527 digits
+ // base 10: 9507 digits
+ // base 16: 7895 digits
+ mediumBase = 3141
+ mediumExponent = 2718
+
+ // 3141**2178
+ // base 2: 406078 digits
+ // base 8: 135360 digits
+ // base 10: 122243 digits
+ // base 16: 101521 digits
+ longBase = 31415
+ longExponent = 27182
+)
+
+func BenchmarkScanShort2(b *testing.B) {
+ ScanHelper(b, 2, shortBase, shortExponent)
+}
+
+func BenchmarkScanShort8(b *testing.B) {
+ ScanHelper(b, 8, shortBase, shortExponent)
+}
+
+func BenchmarkScanSort10(b *testing.B) {
+ ScanHelper(b, 10, shortBase, shortExponent)
+}
+
+func BenchmarkScanShort16(b *testing.B) {
+ ScanHelper(b, 16, shortBase, shortExponent)
+}
+
+func BenchmarkScanMedium2(b *testing.B) {
+ ScanHelper(b, 2, mediumBase, mediumExponent)
+}
+
+func BenchmarkScanMedium8(b *testing.B) {
+ ScanHelper(b, 8, mediumBase, mediumExponent)
+}
+
+func BenchmarkScanMedium10(b *testing.B) {
+ ScanHelper(b, 10, mediumBase, mediumExponent)
+}
+
+func BenchmarkScanMedium16(b *testing.B) {
+ ScanHelper(b, 16, mediumBase, mediumExponent)
+}
+
+func BenchmarkScanLong2(b *testing.B) {
+ ScanHelper(b, 2, longBase, longExponent)
+}
+
+func BenchmarkScanLong8(b *testing.B) {
+ ScanHelper(b, 8, longBase, longExponent)
+}
+
+func BenchmarkScanLong10(b *testing.B) {
+ ScanHelper(b, 10, longBase, longExponent)
+}
+
+func BenchmarkScanLong16(b *testing.B) {
+ ScanHelper(b, 16, longBase, longExponent)
+}
+
+func ScanHelper(b *testing.B, base int, xv, yv Word) {
+ b.StopTimer()
+ var x, y, z nat
+ x = x.setWord(xv)
+ y = y.setWord(yv)
+ z = z.expNN(x, y, nil)
+
+ var s string
+ s = z.string(lowercaseDigits[0:base])
+ if t := toString(z, lowercaseDigits[0:base]); t != s {
+ panic(fmt.Sprintf("scanning: got %s; want %s", s, t))
+ }
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ x.scan(strings.NewReader(s), base)
+ }
+}
+
+func BenchmarkStringShort2(b *testing.B) {
+ StringHelper(b, 2, shortBase, shortExponent)
+}
+
+func BenchmarkStringShort8(b *testing.B) {
+ StringHelper(b, 8, shortBase, shortExponent)
+}
+
+func BenchmarkStringShort10(b *testing.B) {
+ StringHelper(b, 10, shortBase, shortExponent)
+}
+
+func BenchmarkStringShort16(b *testing.B) {
+ StringHelper(b, 16, shortBase, shortExponent)
+}
+
+func BenchmarkStringMedium2(b *testing.B) {
+ StringHelper(b, 2, mediumBase, mediumExponent)
+}
+
+func BenchmarkStringMedium8(b *testing.B) {
+ StringHelper(b, 8, mediumBase, mediumExponent)
+}
+
+func BenchmarkStringMedium10(b *testing.B) {
+ StringHelper(b, 10, mediumBase, mediumExponent)
+}
+
+func BenchmarkStringMedium16(b *testing.B) {
+ StringHelper(b, 16, mediumBase, mediumExponent)
+}
+
+func BenchmarkStringLong2(b *testing.B) {
+ StringHelper(b, 2, longBase, longExponent)
+}
+
+func BenchmarkStringLong8(b *testing.B) {
+ StringHelper(b, 8, longBase, longExponent)
+}
+
+func BenchmarkStringLong10(b *testing.B) {
+ StringHelper(b, 10, longBase, longExponent)
+}
+
+func BenchmarkStringLong16(b *testing.B) {
+ StringHelper(b, 16, longBase, longExponent)
+}
+
+func StringHelper(b *testing.B, base int, xv, yv Word) {
+ b.StopTimer()
+ var x, y, z nat
+ x = x.setWord(xv)
+ y = y.setWord(yv)
+ z = z.expNN(x, y, nil)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ z.string(lowercaseDigits[0:base])
+ }
+}
func TestLeadingZeros(t *testing.T) {
var x Word = _B >> 1
@@ -210,14 +534,12 @@ func TestLeadingZeros(t *testing.T) {
}
}
-
type shiftTest struct {
in nat
shift uint
out nat
}
-
var leftShiftTests = []shiftTest{
{nil, 0, nil},
{nil, 1, nil},
@@ -227,7 +549,6 @@ var leftShiftTests = []shiftTest{
{nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
}
-
func TestShiftLeft(t *testing.T) {
for i, test := range leftShiftTests {
var z nat
@@ -241,7 +562,6 @@ func TestShiftLeft(t *testing.T) {
}
}
-
var rightShiftTests = []shiftTest{
{nil, 0, nil},
{nil, 1, nil},
@@ -252,7 +572,6 @@ var rightShiftTests = []shiftTest{
{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
@@ -266,24 +585,20 @@ func TestShiftRight(t *testing.T) {
}
}
-
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)
@@ -297,7 +612,6 @@ func runModWTests(t *testing.T, tests []modWTest) {
}
}
-
func TestModW(t *testing.T) {
if _W >= 32 {
runModWTests(t, modWTests32)
@@ -307,7 +621,6 @@ func TestModW(t *testing.T) {
}
}
-
func TestTrailingZeroBits(t *testing.T) {
var x Word
x--
@@ -319,7 +632,6 @@ func TestTrailingZeroBits(t *testing.T) {
}
}
-
var expNNTests = []struct {
x, y, m string
out string
@@ -337,17 +649,16 @@ var expNNTests = []struct {
},
}
-
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)
+ x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0)
+ y, _, _ := nat(nil).scan(strings.NewReader(test.y), 0)
+ out, _, _ := nat(nil).scan(strings.NewReader(test.out), 0)
var m nat
if len(test.m) > 0 {
- m, _, _ = nat(nil).scan(test.m, 0)
+ m, _, _ = nat(nil).scan(strings.NewReader(test.m), 0)
}
z := nat(nil).expNN(x, y, m)
diff --git a/libgo/go/big/rat.go b/libgo/go/big/rat.go
index e70673a1cba..327b9bd9ca7 100644
--- a/libgo/go/big/rat.go
+++ b/libgo/go/big/rat.go
@@ -6,7 +6,12 @@
package big
-import "strings"
+import (
+ "encoding/binary"
+ "fmt"
+ "os"
+ "strings"
+)
// A Rat represents a quotient a/b of arbitrary precision. The zero value for
// a Rat, 0/0, is not a legal Rat.
@@ -15,13 +20,11 @@ type Rat struct {
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)
@@ -30,7 +33,6 @@ func (z *Rat) SetFrac(a, b *Int) *Rat {
return z.norm()
}
-
// SetFrac64 sets z to a/b and returns z.
func (z *Rat) SetFrac64(a, b int64) *Rat {
z.a.SetInt64(a)
@@ -42,7 +44,6 @@ func (z *Rat) SetFrac64(a, b int64) *Rat {
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)
@@ -50,7 +51,6 @@ func (z *Rat) SetInt(x *Int) *Rat {
return z
}
-
// SetInt64 sets z to x and returns z.
func (z *Rat) SetInt64(x int64) *Rat {
z.a.SetInt64(x)
@@ -58,7 +58,6 @@ func (z *Rat) SetInt64(x int64) *Rat {
return z
}
-
// Sign returns:
//
// -1 if x < 0
@@ -69,13 +68,11 @@ 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.
@@ -83,15 +80,13 @@ func (z *Rat) Num() *Int {
return &z.a
}
-
-// Demom returns the denominator of z; it is always > 0.
+// Denom 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
@@ -106,7 +101,6 @@ func gcd(x, y nat) nat {
return a
}
-
func (z *Rat) norm() *Rat {
f := gcd(z.a.abs, z.b)
if len(z.a.abs) == 0 {
@@ -122,7 +116,6 @@ func (z *Rat) norm() *Rat {
return z
}
-
func mulNat(x *Int, y nat) *Int {
var z Int
z.abs = z.abs.mul(x.abs, y)
@@ -130,7 +123,6 @@ func mulNat(x *Int, y nat) *Int {
return &z
}
-
// Cmp compares x and y and returns:
//
// -1 if x < y
@@ -141,7 +133,6 @@ 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)
@@ -149,7 +140,6 @@ func (z *Rat) Abs(x *Rat) *Rat {
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)
@@ -159,7 +149,6 @@ func (z *Rat) Add(x, y *Rat) *Rat {
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)
@@ -169,7 +158,6 @@ func (z *Rat) Sub(x, y *Rat) *Rat {
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)
@@ -177,7 +165,6 @@ func (z *Rat) Mul(x, y *Rat) *Rat {
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 {
@@ -192,7 +179,6 @@ func (z *Rat) Quo(x, y *Rat) *Rat {
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)
@@ -200,7 +186,6 @@ func (z *Rat) Neg(x *Rat) *Rat {
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)
@@ -208,6 +193,25 @@ func (z *Rat) Set(x *Rat) *Rat {
return z
}
+func ratTok(ch int) bool {
+ return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+}
+
+// Scan is a support routine for fmt.Scanner. It accepts the formats
+// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
+func (z *Rat) Scan(s fmt.ScanState, ch int) os.Error {
+ tok, err := s.Token(true, ratTok)
+ if err != nil {
+ return err
+ }
+ if strings.IndexRune("efgEFGv", ch) < 0 {
+ return os.NewError("Rat.Scan: invalid verb")
+ }
+ if _, ok := z.SetString(string(tok)); !ok {
+ return os.NewError("Rat.Scan: invalid syntax")
+ }
+ return nil
+}
// 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
@@ -225,8 +229,8 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
return z, false
}
s = s[sep+1:]
- var n int
- if z.b, _, n = z.b.scan(s, 10); n != len(s) {
+ var err os.Error
+ if z.b, _, err = z.b.scan(strings.NewReader(s), 10); err != nil {
return z, false
}
return z.norm(), true
@@ -267,13 +271,11 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
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)
+ return z.a.String() + "/" + z.b.decimalString()
}
-
// 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 {
@@ -283,12 +285,15 @@ func (z *Rat) RatString() 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()
+ s := z.a.String()
+ if prec > 0 {
+ s += "." + strings.Repeat("0", prec)
+ }
+ return s
}
q, r := nat{}.div(nat{}, z.a.abs, z.b)
@@ -311,16 +316,56 @@ func (z *Rat) FloatString(prec int) string {
}
}
- s := q.string(10)
+ s := q.decimalString()
if z.a.neg {
s = "-" + s
}
if prec > 0 {
- rs := r.string(10)
+ rs := r.decimalString()
leadingZeros := prec - len(rs)
s += "." + strings.Repeat("0", leadingZeros) + rs
}
return s
}
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const ratGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (z *Rat) GobEncode() ([]byte, os.Error) {
+ buf := make([]byte, 1+4+(len(z.a.abs)+len(z.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+ i := z.b.bytes(buf)
+ j := z.a.abs.bytes(buf[0:i])
+ n := i - j
+ if int(uint32(n)) != n {
+ // this should never happen
+ return nil, os.NewError("Rat.GobEncode: numerator too large")
+ }
+ binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
+ j -= 1 + 4
+ b := ratGobVersion << 1 // make space for sign bit
+ if z.a.neg {
+ b |= 1
+ }
+ buf[j] = b
+ return buf[j:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Rat) GobDecode(buf []byte) os.Error {
+ if len(buf) == 0 {
+ return os.NewError("Rat.GobDecode: no data")
+ }
+ b := buf[0]
+ if b>>1 != ratGobVersion {
+ return os.NewError(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
+ }
+ const j = 1 + 4
+ i := j + binary.BigEndian.Uint32(buf[j-4:j])
+ z.a.neg = b&1 != 0
+ z.a.abs = z.a.abs.setBytes(buf[j:i])
+ z.b = z.b.setBytes(buf[i:])
+ return nil
+}
diff --git a/libgo/go/big/rat_test.go b/libgo/go/big/rat_test.go
index 8f42949b087..dbc5bb6cca1 100644
--- a/libgo/go/big/rat_test.go
+++ b/libgo/go/big/rat_test.go
@@ -4,8 +4,12 @@
package big
-import "testing"
-
+import (
+ "bytes"
+ "fmt"
+ "gob"
+ "testing"
+)
var setStringTests = []struct {
in, out string
@@ -52,6 +56,27 @@ func TestRatSetString(t *testing.T) {
}
}
+func TestRatScan(t *testing.T) {
+ var buf bytes.Buffer
+ for i, test := range setStringTests {
+ x := new(Rat)
+ buf.Reset()
+ buf.WriteString(test.in)
+
+ _, err := fmt.Fscanf(&buf, "%v", x)
+ if err == nil != test.ok {
+ if test.ok {
+ t.Errorf("#%d error: %s", i, err.String())
+ } else {
+ t.Errorf("#%d expected error", i)
+ }
+ continue
+ }
+ if err == nil && x.RatString() != test.out {
+ t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+ }
+ }
+}
var floatStringTests = []struct {
in string
@@ -59,12 +84,13 @@ var floatStringTests = []struct {
out string
}{
{"0", 0, "0"},
- {"0", 4, "0"},
+ {"0", 4, "0.0000"},
{"1", 0, "1"},
- {"1", 2, "1"},
+ {"1", 2, "1.00"},
{"-1", 0, "-1"},
{".25", 2, "0.25"},
{".25", 1, "0.3"},
+ {".25", 3, "0.250"},
{"-1/3", 3, "-0.333"},
{"-2/3", 4, "-0.6667"},
{"0.96", 1, "1.0"},
@@ -84,7 +110,6 @@ func TestFloatString(t *testing.T) {
}
}
-
func TestRatSign(t *testing.T) {
zero := NewRat(0, 1)
for _, a := range setStringTests {
@@ -98,7 +123,6 @@ func TestRatSign(t *testing.T) {
}
}
-
var ratCmpTests = []struct {
rat1, rat2 string
out int
@@ -126,7 +150,6 @@ func TestRatCmp(t *testing.T) {
}
}
-
func TestIsInt(t *testing.T) {
one := NewInt(1)
for _, a := range setStringTests {
@@ -140,7 +163,6 @@ func TestIsInt(t *testing.T) {
}
}
-
func TestRatAbs(t *testing.T) {
zero := NewRat(0, 1)
for _, a := range setStringTests {
@@ -158,7 +180,6 @@ func TestRatAbs(t *testing.T) {
}
}
-
type ratBinFun func(z, x, y *Rat) *Rat
type ratBinArg struct {
x, y, z string
@@ -175,7 +196,6 @@ func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
}
}
-
var ratBinTests = []struct {
x, y string
sum, prod string
@@ -232,7 +252,6 @@ func TestRatBin(t *testing.T) {
}
}
-
func TestIssue820(t *testing.T) {
x := NewRat(3, 1)
y := NewRat(2, 1)
@@ -258,7 +277,6 @@ func TestIssue820(t *testing.T) {
}
}
-
var setFrac64Tests = []struct {
a, b int64
out string
@@ -280,3 +298,35 @@ func TestRatSetFrac64Rat(t *testing.T) {
}
}
}
+
+func TestRatGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for i, test := range gobEncodingTests {
+ for j := 0; j < 4; j++ {
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ stest := test
+ if j&1 != 0 {
+ // negative numbers
+ stest = "-" + test
+ }
+ if j%2 != 0 {
+ // fractions
+ stest = stest + "." + test
+ }
+ var tx Rat
+ tx.SetString(stest)
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
+ }
+ var rx Rat
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx)
+ }
+ }
+ }
+}
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
index eaae8bb42c3..727ebfdbbe2 100644
--- a/libgo/go/bufio/bufio.go
+++ b/libgo/go/bufio/bufio.go
@@ -15,16 +15,17 @@ import (
"utf8"
)
-
const (
defaultBufSize = 4096
)
// Errors introduced by this package.
type Error struct {
- os.ErrorString
+ ErrorString string
}
+func (err *Error) String() string { return err.ErrorString }
+
var (
ErrInvalidUnreadByte os.Error = &Error{"bufio: invalid use of UnreadByte"}
ErrInvalidUnreadRune os.Error = &Error{"bufio: invalid use of UnreadRune"}
@@ -40,7 +41,6 @@ func (b BufSizeError) String() string {
return "bufio: bad buffer size " + strconv.Itoa(int(b))
}
-
// Buffered input.
// Reader implements buffering for an io.Reader object.
@@ -101,6 +101,12 @@ func (b *Reader) fill() {
}
}
+func (b *Reader) readErr() os.Error {
+ err := b.err
+ b.err = nil
+ return err
+}
+
// 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
@@ -119,7 +125,7 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
if m > n {
m = n
}
- err := b.err
+ err := b.readErr()
if m < n && err == nil {
err = ErrBufferFull
}
@@ -134,11 +140,11 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) {
func (b *Reader) Read(p []byte) (n int, err os.Error) {
n = len(p)
if n == 0 {
- return 0, b.err
+ return 0, b.readErr()
}
if b.w == b.r {
if b.err != nil {
- return 0, b.err
+ return 0, b.readErr()
}
if len(p) >= len(b.buf) {
// Large read, empty buffer.
@@ -148,11 +154,11 @@ func (b *Reader) Read(p []byte) (n int, err os.Error) {
b.lastByte = int(p[n-1])
b.lastRuneSize = -1
}
- return n, b.err
+ return n, b.readErr()
}
b.fill()
if b.w == b.r {
- return 0, b.err
+ return 0, b.readErr()
}
}
@@ -172,7 +178,7 @@ 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
+ return 0, b.readErr()
}
b.fill()
}
@@ -208,7 +214,7 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
}
b.lastRuneSize = -1
if b.r == b.w {
- return 0, 0, b.err
+ return 0, 0, b.readErr()
}
rune, size = int(b.buf[b.r]), 1
if rune >= 0x80 {
@@ -260,7 +266,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
if b.err != nil {
line := b.buf[b.r:b.w]
b.r = b.w
- return line, b.err
+ return line, b.readErr()
}
n := b.Buffered()
@@ -367,7 +373,6 @@ func (b *Reader) ReadString(delim byte) (line string, err os.Error) {
return string(bytes), e
}
-
// buffered output
// Writer implements buffering for an io.Writer object.
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
index 123adac29a4..82c73d36a9c 100644
--- a/libgo/go/bufio/bufio_test.go
+++ b/libgo/go/bufio/bufio_test.go
@@ -53,11 +53,12 @@ func readBytes(buf *Reader) string {
if e == os.EOF {
break
}
- if e != nil {
+ if e == nil {
+ b[nb] = c
+ nb++
+ } else if e != iotest.ErrTimeout {
panic("Data: " + e.String())
}
- b[nb] = c
- nb++
}
return string(b[0:nb])
}
@@ -75,7 +76,6 @@ func TestReaderSimple(t *testing.T) {
}
}
-
type readMaker struct {
name string
fn func(io.Reader) io.Reader
@@ -86,6 +86,7 @@ var readMakers = []readMaker{
{"byte", iotest.OneByteReader},
{"half", iotest.HalfReader},
{"data+err", iotest.DataErrReader},
+ {"timeout", iotest.TimeoutReader},
}
// Call ReadString (which ends up calling everything else)
@@ -97,7 +98,7 @@ func readLines(b *Reader) string {
if e == os.EOF {
break
}
- if e != nil {
+ if e != nil && e != iotest.ErrTimeout {
panic("GetLines: " + e.String())
}
s += s1
diff --git a/libgo/go/builtin/builtin.go b/libgo/go/builtin/builtin.go
new file mode 100644
index 00000000000..07acce4f700
--- /dev/null
+++ b/libgo/go/builtin/builtin.go
@@ -0,0 +1,135 @@
+// 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 builtin provides documentation for Go's built-in functions.
+ The functions documented here are not actually in package builtin
+ but their descriptions here allow godoc to present documentation
+ for the language's special functions.
+*/
+package builtin
+
+// Type is here for the purposes of documentation only. It is a stand-in
+// for any Go type, but represents the same type for any given function
+// invocation.
+type Type int
+
+// IntegerType is here for the purposes of documentation only. It is a stand-in
+// for any integer type: int, uint, int8 etc.
+type IntegerType int
+
+// FloatType is here for the purposes of documentation only. It is a stand-in
+// for either float type: float32 or float64.
+type FloatType int
+
+// ComplexType is here for the purposes of documentation only. It is a
+// stand-in for either complex type: complex64 or complex128.
+type ComplexType int
+
+// The append built-in function appends elements to the end of a slice. If
+// it has sufficient capacity, the destination is resliced to accommodate the
+// new elements. If it does not, a new underlying array will be allocated.
+// Append returns the updated slice. It is therefore necessary to store the
+// result of append, often in the variable holding the slice itself:
+// slice = append(slice, elem1, elem2)
+// slice = append(slice, anotherSlice...)
+func append(slice []Type, elems ...Type) []Type
+
+// The copy built-in function copies elements from a source slice into a
+// destination slice. (As a special case, it also will copy bytes from a
+// string to a slice of bytes.) The source and destination may overlap. Copy
+// returns the number of elements copied, which will be the minimum of
+// len(src) and len(dst).
+func copy(dst, src []Type) int
+
+// The len built-in function returns the length of v, according to its type:
+// Array: the number of elements in v.
+// Pointer to array: the number of elements in *v (even if v is nil).
+// Slice, or map: the number of elements in v; if v is nil, len(v) is zero.
+// String: the number of bytes in v.
+// Channel: the number of elements queued (unread) in the channel buffer;
+// if v is nil, len(v) is zero.
+func len(v Type) int
+
+// The cap built-in function returns the capacity of v, according to its type:
+// Array: the number of elements in v (same as len(v)).
+// Pointer to array: the number of elements in *v (same as len(v)).
+// Slice: the maximum length the slice can reach when resliced;
+// if v is nil, cap(v) is zero.
+// Channel: the channel buffer capacity, in units of elements;
+// if v is nil, cap(v) is zero.
+func cap(v Type) int
+
+// The make built-in function allocates and initializes an object of type
+// slice, map, or chan (only). Like new, the first argument is a type, not a
+// value. Unlike new, make's return type is the same as the type of its
+// argument, not a pointer to it. The specification of the result depends on
+// the type:
+// Slice: The size specifies the length. The capacity of the slice is
+// equal to its length. A second integer argument may be provided to
+// specify a different capacity; it must be no smaller than the
+// length, so make([]int, 0, 10) allocates a slice of length 0 and
+// capacity 10.
+// Map: An initial allocation is made according to the size but the
+// resulting map has length 0. The size may be omitted, in which case
+// a small starting size is allocated.
+// Channel: The channel's buffer is initialized with the specified
+// buffer capacity. If zero, or the size is omitted, the channel is
+// unbuffered.
+func make(Type, size IntegerType) Type
+
+// The new built-in function allocates memory. The first argument is a type,
+// not a value, and the value returned is a pointer to a newly
+// allocated zero value of that type.
+func new(Type) *Type
+
+// The complex built-in function constructs a complex value from two
+// floating-point values. The real and imaginary parts must be of the same
+// size, either float32 or float64 (or assignable to them), and the return
+// value will be the corresponding complex type (complex64 for float32,
+// complex128 for float64).
+func complex(r, i FloatType) ComplexType
+
+// The real built-in function returns the real part of the complex number c.
+// The return value will be floating point type corresponding to the type of c.
+func real(c ComplexType) FloatType
+
+// The imaginary built-in function returns the imaginary part of the complex
+// number c. The return value will be floating point type corresponding to
+// the type of c.
+func imag(c ComplexType) FloatType
+
+// The close built-in function closes a channel, which must be either
+// bidirectional or send-only. It should be executed only by the sender,
+// never the receiver, and has the effect of shutting down the channel after
+// the last sent value is received. After the last value has been received
+// from a closed channel c, any receive from c will succeed without
+// blocking, returning the zero value for the channel element. The form
+// x, ok := <-c
+// will also set ok to false for a closed channel.
+func close(c chan<- Type)
+
+// The panic built-in function stops normal execution of the current
+// goroutine. When a function F calls panic, normal execution of F stops
+// immediately. Any functions whose execution was deferred by F are run in
+// the usual way, and then F returns to its caller. To the caller G, the
+// invocation of F then behaves like a call to panic, terminating G's
+// execution and running any deferred functions. This continues until all
+// functions in the executing goroutine have stopped, in reverse order. At
+// that point, the program is terminated and the error condition is reported,
+// including the value of the argument to panic. This termination sequence
+// is called panicking and can be controlled by the built-in function
+// recover.
+func panic(v interface{})
+
+// The recover built-in function allows a program to manage behavior of a
+// panicking goroutine. Executing a call to recover inside a deferred
+// function (but not any function called by it) stops the panicking sequence
+// by restoring normal execution and retrieves the error value passed to the
+// call of panic. If recover is called outside the deferred function it will
+// not stop a panicking sequence. In this case, or when the goroutine is not
+// panicking, or if the argument supplied to panic was nil, recover returns
+// nil. Thus the return value from recover reports whether the goroutine is
+// panicking.
+func recover() interface{}
diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go
index 1acd4e05cae..5de86105d05 100644
--- a/libgo/go/bytes/buffer.go
+++ b/libgo/go/bytes/buffer.go
@@ -280,7 +280,7 @@ func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
// from any read operation.)
func (b *Buffer) UnreadRune() os.Error {
if b.lastRead != opReadRune {
- return os.ErrorString("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
+ return os.NewError("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
}
b.lastRead = opInvalid
if b.off > 0 {
@@ -295,7 +295,7 @@ func (b *Buffer) UnreadRune() os.Error {
// returns an error.
func (b *Buffer) UnreadByte() os.Error {
if b.lastRead != opReadRune && b.lastRead != opRead {
- return os.ErrorString("bytes.Buffer: UnreadByte: previous operation was not a read")
+ return os.NewError("bytes.Buffer: UnreadByte: previous operation was not a read")
}
b.lastRead = opInvalid
if b.off > 0 {
diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go
index 14f9501416e..06d2a65c673 100644
--- a/libgo/go/bytes/buffer_test.go
+++ b/libgo/go/bytes/buffer_test.go
@@ -12,7 +12,6 @@ import (
"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.
@@ -47,7 +46,6 @@ func check(t *testing.T, testname string, buf *Buffer, s string) {
}
}
-
// 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.
@@ -67,7 +65,6 @@ func fillString(t *testing.T, testname string, buf *Buffer, s string, n int, fus
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.
@@ -87,19 +84,16 @@ func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub
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) {
@@ -120,7 +114,6 @@ func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) {
check(t, testname+" (empty 4)", buf, "")
}
-
func TestBasicOperations(t *testing.T) {
var buf Buffer
@@ -175,7 +168,6 @@ func TestBasicOperations(t *testing.T) {
}
}
-
func TestLargeStringWrites(t *testing.T) {
var buf Buffer
limit := 30
@@ -189,7 +181,6 @@ func TestLargeStringWrites(t *testing.T) {
check(t, "TestLargeStringWrites (3)", &buf, "")
}
-
func TestLargeByteWrites(t *testing.T) {
var buf Buffer
limit := 30
@@ -203,7 +194,6 @@ func TestLargeByteWrites(t *testing.T) {
check(t, "TestLargeByteWrites (3)", &buf, "")
}
-
func TestLargeStringReads(t *testing.T) {
var buf Buffer
for i := 3; i < 30; i += 3 {
@@ -213,7 +203,6 @@ func TestLargeStringReads(t *testing.T) {
check(t, "TestLargeStringReads (3)", &buf, "")
}
-
func TestLargeByteReads(t *testing.T) {
var buf Buffer
for i := 3; i < 30; i += 3 {
@@ -223,7 +212,6 @@ func TestLargeByteReads(t *testing.T) {
check(t, "TestLargeByteReads (3)", &buf, "")
}
-
func TestMixedReadsAndWrites(t *testing.T) {
var buf Buffer
s := ""
@@ -243,7 +231,6 @@ func TestMixedReadsAndWrites(t *testing.T) {
empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
}
-
func TestNil(t *testing.T) {
var b *Buffer
if b.String() != "<nil>" {
@@ -251,7 +238,6 @@ func TestNil(t *testing.T) {
}
}
-
func TestReadFrom(t *testing.T) {
var buf Buffer
for i := 3; i < 30; i += 3 {
@@ -262,7 +248,6 @@ func TestReadFrom(t *testing.T) {
}
}
-
func TestWriteTo(t *testing.T) {
var buf Buffer
for i := 3; i < 30; i += 3 {
@@ -273,7 +258,6 @@ func TestWriteTo(t *testing.T) {
}
}
-
func TestRuneIO(t *testing.T) {
const NRune = 1000
// Built a test array while we write the data
@@ -323,7 +307,6 @@ func TestRuneIO(t *testing.T) {
}
}
-
func TestNext(t *testing.T) {
b := []byte{0, 1, 2, 3, 4}
tmp := make([]byte, 5)
diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go
index 0f9ac986371..5119fce949e 100644
--- a/libgo/go/bytes/bytes.go
+++ b/libgo/go/bytes/bytes.go
@@ -212,26 +212,40 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
return a[0 : na+1]
}
-// Split slices s into subslices separated by sep and returns a slice of
+// SplitN 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.
+// If sep is empty, SplitN 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) }
+func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
-// SplitAfter slices s into subslices after each instance of sep and
+// SplitAfterN 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.
+// If sep is empty, SplitAfterN 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 {
+func SplitAfterN(s, sep []byte, n int) [][]byte {
return genSplit(s, sep, len(sep), n)
}
+// Split slices s into all 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.
+// It is equivalent to SplitN with a count of -1.
+func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) }
+
+// SplitAfter slices s into all subslices after each instance of sep and
+// returns a slice of those subslices.
+// If sep is empty, SplitAfter splits after each UTF-8 sequence.
+// It is equivalent to SplitAfterN with a count of -1.
+func SplitAfter(s, sep []byte) [][]byte {
+ return genSplit(s, sep, len(sep), -1)
+}
+
// 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 {
@@ -384,7 +398,6 @@ 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 {
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
index 4ce291a4f67..9444358a858 100644
--- a/libgo/go/bytes/bytes_test.go
+++ b/libgo/go/bytes/bytes_test.go
@@ -6,6 +6,7 @@ package bytes_test
import (
. "bytes"
+ "reflect"
"testing"
"unicode"
"utf8"
@@ -315,7 +316,7 @@ var explodetests = []ExplodeTest{
func TestExplode(t *testing.T) {
for _, tt := range explodetests {
- a := Split([]byte(tt.s), nil, tt.n)
+ a := SplitN([]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)
@@ -328,7 +329,6 @@ func TestExplode(t *testing.T) {
}
}
-
type SplitTest struct {
s string
sep string
@@ -354,7 +354,7 @@ var splittests = []SplitTest{
func TestSplit(t *testing.T) {
for _, tt := range splittests {
- a := Split([]byte(tt.s), []byte(tt.sep), tt.n)
+ a := SplitN([]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)
@@ -367,6 +367,12 @@ func TestSplit(t *testing.T) {
if string(s) != tt.s {
t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
}
+ if tt.n < 0 {
+ b := Split([]byte(tt.s), []byte(tt.sep))
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+ }
+ }
}
}
@@ -388,7 +394,7 @@ var splitaftertests = []SplitTest{
func TestSplitAfter(t *testing.T) {
for _, tt := range splitaftertests {
- a := SplitAfter([]byte(tt.s), []byte(tt.sep), tt.n)
+ a := SplitAfterN([]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)
@@ -398,6 +404,12 @@ func TestSplitAfter(t *testing.T) {
if string(s) != tt.s {
t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
}
+ if tt.n < 0 {
+ b := SplitAfter([]byte(tt.s), []byte(tt.sep))
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+ }
+ }
}
}
@@ -649,7 +661,6 @@ func TestRunes(t *testing.T) {
}
}
-
type TrimTest struct {
f func([]byte, string) []byte
in, cutset, out string
diff --git a/libgo/go/compress/bzip2/bzip2.go b/libgo/go/compress/bzip2/bzip2.go
index 9e97edec175..8b4572306b1 100644
--- a/libgo/go/compress/bzip2/bzip2.go
+++ b/libgo/go/compress/bzip2/bzip2.go
@@ -284,7 +284,7 @@ func (bz2 *reader) readBlock() (err os.Error) {
repeat := 0
repeat_power := 0
- // The `C' array (used by the inverse BWT) needs to be zero initialised.
+ // The `C' array (used by the inverse BWT) needs to be zero initialized.
for i := range bz2.c {
bz2.c[i] = 0
}
@@ -330,7 +330,7 @@ func (bz2 *reader) readBlock() (err os.Error) {
if int(v) == numSymbols-1 {
// This is the EOF symbol. Because it's always at the
- // end of the move-to-front list, and nevers gets moved
+ // end of the move-to-front list, and never gets moved
// to the front, it has this unique value.
break
}
diff --git a/libgo/go/compress/bzip2/huffman.go b/libgo/go/compress/bzip2/huffman.go
index 732bc4a21da..dc05739c755 100644
--- a/libgo/go/compress/bzip2/huffman.go
+++ b/libgo/go/compress/bzip2/huffman.go
@@ -68,7 +68,7 @@ func newHuffmanTree(lengths []uint8) (huffmanTree, os.Error) {
// each symbol (consider reflecting a tree down the middle, for
// example). Since the code length assignments determine the
// efficiency of the tree, each of these trees is equally good. In
- // order to minimise the amount of information needed to build a tree
+ // order to minimize the amount of information needed to build a tree
// bzip2 uses a canonical tree so that it can be reconstructed given
// only the code length assignments.
diff --git a/libgo/go/compress/flate/deflate.go b/libgo/go/compress/flate/deflate.go
index a02a5e8d94b..b1cee0b2f0f 100644
--- a/libgo/go/compress/flate/deflate.go
+++ b/libgo/go/compress/flate/deflate.go
@@ -11,16 +11,18 @@ import (
)
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
+ NoCompression = 0
+ BestSpeed = 1
+ fastCompression = 3
+ BestCompression = 9
+ DefaultCompression = -1
+ logWindowSize = 15
+ windowSize = 1 << logWindowSize
+ windowMask = windowSize - 1
+ logMaxOffsetSize = 15 // Standard 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.
@@ -32,22 +34,6 @@ const (
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
}
@@ -68,105 +54,73 @@ var levels = []compressionLevel{
{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
+ compressionLevel
- eof bool // has eof been reached on input?
- sync bool // writer wants to flush
- syncChan chan os.Error
+ w *huffmanBitWriter
- // hashHead[hashValue] contains the largest inputIndex with the specified hash value
- hashHead []int
+ // compression algorithm
+ fill func(*compressor, []byte) int // copy data to window
+ step func(*compressor) // process window
+ sync bool // requesting flush
+ // Input hash chains
+ // hashHead[hashValue] contains the largest inputIndex with the specified hash value
// 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
+ chainHead int
+ hashHead []int
+ hashPrev []int
+
+ // input window: unprocessed data is window[index:windowEnd]
+ index int
+ window []byte
+ windowEnd int
+ blockStart int // window index where current tokens start
+ byteAvailable bool // if true, still need to process window[index-1].
+
+ // queued output tokens: tokens[:ti]
+ tokens []token
+ ti int
+
+ // deflate state
+ length int
+ offset int
+ hash int
+ maxInsertIndex int
+ err os.Error
}
-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
+func (d *compressor) fillDeflate(b []byte) int {
+ if d.index >= 2*windowSize-(minMatchLength+maxMatchLength) {
+ // shift the window by windowSize
+ copy(d.window, d.window[windowSize:2*windowSize])
+ d.index -= windowSize
+ d.windowEnd -= windowSize
+ if d.blockStart >= windowSize {
+ d.blockStart -= windowSize
} else {
d.blockStart = math.MaxInt32
}
for i, h := range d.hashHead {
- v := h - wSize
+ v := h - windowSize
if v < -1 {
v = -1
}
d.hashHead[i] = v
}
for i, h := range d.hashPrev {
- v := -h - wSize
+ v := -h - windowSize
if v < -1 {
v = -1
}
d.hashPrev[i] = v
}
}
- 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
+ n := copy(d.window[d.windowEnd:], b)
+ d.windowEnd += n
+ return n
}
func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error {
@@ -194,21 +148,21 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead
// We quit when we get a match that's at least nice long
nice := len(win) - pos
- if d.niceMatch < nice {
- nice = d.niceMatch
+ if d.nice < nice {
+ nice = d.nice
}
// If we've got a match that's good enough, only look in 1/4 the chain.
- tries := d.maxChainLength
+ tries := d.chain
length = prevLength
- if length >= d.goodMatch {
+ if length >= d.good {
tries >>= 2
}
w0 := win[pos]
w1 := win[pos+1]
wEnd := win[pos+length]
- minIndex := pos - (d.windowMask + 1)
+ minIndex := pos - windowSize
for i := prevHead; tries > 0; tries-- {
if w0 == win[i] && w1 == win[i+1] && wEnd == win[i+length] {
@@ -233,7 +187,7 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead
// hashPrev[i & windowMask] has already been overwritten, so stop now.
break
}
- if i = d.hashPrev[i&d.windowMask]; i < minIndex || i < 0 {
+ if i = d.hashPrev[i&windowMask]; i < minIndex || i < 0 {
break
}
}
@@ -248,234 +202,224 @@ func (d *compressor) writeStoredBlock(buf []byte) os.Error {
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
+func (d *compressor) initDeflate() {
d.hashHead = make([]int, hashSize)
- d.hashPrev = make([]int, 1<<d.logWindowSize)
- d.window = make([]byte, 2<<d.logWindowSize)
+ d.hashPrev = make([]int, windowSize)
+ d.window = make([]byte, 2*windowSize)
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 {
+ d.tokens = make([]token, maxFlateBlockTokens, maxFlateBlockTokens+1)
+ d.length = minMatchLength - 1
+ d.offset = 0
+ d.byteAvailable = false
+ d.index = 0
+ d.ti = 0
+ d.hash = 0
+ d.chainHead = -1
+}
+
+func (d *compressor) deflate() {
+ if d.windowEnd-d.index < minMatchLength+maxMatchLength && !d.sync {
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])
+
+ d.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
+ if d.index < d.maxInsertIndex {
+ d.hash = int(d.window[d.index])<<hashShift + int(d.window[d.index+1])
}
- chainHead := -1
+
Loop:
for {
- if index > windowEnd {
+ if d.index > d.windowEnd {
panic("index > windowEnd")
}
- lookahead := windowEnd - index
+ lookahead := d.windowEnd - d.index
if lookahead < minMatchLength+maxMatchLength {
- if index, err = d.fillWindow(index); err != nil {
- return
+ if !d.sync {
+ break Loop
}
- windowEnd = d.windowEnd
- if index > windowEnd {
+ if d.index > d.windowEnd {
panic("index > windowEnd")
}
- maxInsertIndex = windowEnd - (minMatchLength - 1)
- lookahead = windowEnd - index
if lookahead == 0 {
// Flush current output block if any.
- if byteAvailable {
+ if d.byteAvailable {
// There is still one pending token that needs to be flushed
- tokens[ti] = literalToken(uint32(d.window[index-1]) & 0xFF)
- ti++
- byteAvailable = false
+ d.tokens[d.ti] = literalToken(uint32(d.window[d.index-1]))
+ d.ti++
+ d.byteAvailable = false
}
- if ti > 0 {
- if err = d.writeBlock(tokens[0:ti], index, false); err != nil {
+ if d.ti > 0 {
+ if d.err = d.writeBlock(d.tokens[0:d.ti], d.index, false); d.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
+ d.ti = 0
}
break Loop
}
}
- if index < maxInsertIndex {
+ if d.index < d.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
+ d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask
+ d.chainHead = d.hashHead[d.hash]
+ d.hashPrev[d.index&windowMask] = d.chainHead
+ d.hashHead[d.hash] = d.index
}
- prevLength := length
- prevOffset := offset
- length = minMatchLength - 1
- offset = 0
- minIndex := index - maxOffset
+ prevLength := d.length
+ prevOffset := d.offset
+ d.length = minMatchLength - 1
+ d.offset = 0
+ minIndex := d.index - windowSize
if minIndex < 0 {
minIndex = 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 d.chainHead >= minIndex &&
+ (d.fastSkipHashing != 0 && lookahead > minMatchLength-1 ||
+ d.fastSkipHashing == 0 && lookahead > prevLength && prevLength < d.lazy) {
+ if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead, minMatchLength-1, lookahead); ok {
+ d.length = newLength
+ d.offset = newOffset
}
}
- if isFastDeflate && length >= minMatchLength ||
- !isFastDeflate && prevLength >= minMatchLength && length <= prevLength {
+ if d.fastSkipHashing != 0 && d.length >= minMatchLength ||
+ d.fastSkipHashing == 0 && prevLength >= minMatchLength && d.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))
+ if d.fastSkipHashing != 0 {
+ d.tokens[d.ti] = matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize))
} else {
- tokens[ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize))
+ d.tokens[d.ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize))
}
- ti++
+ d.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 {
+ if d.length <= d.fastSkipHashing {
var newIndex int
- if isFastDeflate {
- newIndex = index + length
+ if d.fastSkipHashing != 0 {
+ newIndex = d.index + d.length
} else {
newIndex = prevLength - 1
}
- for index++; index < newIndex; index++ {
- if index < maxInsertIndex {
- hash = (hash<<hashShift + int(d.window[index+2])) & hashMask
+ for d.index++; d.index < newIndex; d.index++ {
+ if d.index < d.maxInsertIndex {
+ d.hash = (d.hash<<hashShift + int(d.window[d.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]
+ d.hashPrev[d.index&windowMask] = d.hashHead[d.hash]
// Set the head of the hash chain to us.
- d.hashHead[hash] = index
+ d.hashHead[d.hash] = d.index
}
}
- if !isFastDeflate {
- byteAvailable = false
- length = minMatchLength - 1
+ if d.fastSkipHashing == 0 {
+ d.byteAvailable = false
+ d.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]))
+ d.index += d.length
+ d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1]))
}
- if ti == maxFlateBlockTokens {
+ if d.ti == maxFlateBlockTokens {
// The block includes the current character
- if err = d.writeBlock(tokens, index, false); err != nil {
+ if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
return
}
- ti = 0
+ d.ti = 0
}
} else {
- if isFastDeflate || byteAvailable {
- i := index - 1
- if isFastDeflate {
- i = index
+ if d.fastSkipHashing != 0 || d.byteAvailable {
+ i := d.index - 1
+ if d.fastSkipHashing != 0 {
+ i = d.index
}
- tokens[ti] = literalToken(uint32(d.window[i]) & 0xFF)
- ti++
- if ti == maxFlateBlockTokens {
- if err = d.writeBlock(tokens, i+1, false); err != nil {
+ d.tokens[d.ti] = literalToken(uint32(d.window[i]))
+ d.ti++
+ if d.ti == maxFlateBlockTokens {
+ if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil {
return
}
- ti = 0
+ d.ti = 0
}
}
- index++
- if !isFastDeflate {
- byteAvailable = true
+ d.index++
+ if d.fastSkipHashing == 0 {
+ d.byteAvailable = true
}
}
}
- return
}
-func (d *compressor) compress(r io.Reader, w io.Writer, level int, logWindowSize uint) (err os.Error) {
- d.r = r
+func (d *compressor) fillStore(b []byte) int {
+ n := copy(d.window[d.windowEnd:], b)
+ d.windowEnd += n
+ return n
+}
+
+func (d *compressor) store() {
+ if d.windowEnd > 0 {
+ d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+ }
+ d.windowEnd = 0
+}
+
+func (d *compressor) write(b []byte) (n int, err os.Error) {
+ n = len(b)
+ b = b[d.fill(d, b):]
+ for len(b) > 0 {
+ d.step(d)
+ b = b[d.fill(d, b):]
+ }
+ return n, d.err
+}
+
+func (d *compressor) syncFlush() os.Error {
+ d.sync = true
+ d.step(d)
+ if d.err == nil {
+ d.w.writeStoredHeader(0, false)
+ d.w.flush()
+ d.err = d.w.err
+ }
+ d.sync = false
+ return d.err
+}
+
+func (d *compressor) init(w io.Writer, level int) (err os.Error) {
d.w = newHuffmanBitWriter(w)
- d.level = level
- d.logWindowSize = logWindowSize
switch {
case level == NoCompression:
- err = d.storedDeflate()
+ d.window = make([]byte, maxStoreBlockSize)
+ d.fill = (*compressor).fillStore
+ d.step = (*compressor).store
case level == DefaultCompression:
- d.level = 6
+ level = 6
fallthrough
case 1 <= level && level <= 9:
- err = d.doDeflate()
+ d.compressionLevel = levels[level]
+ d.initDeflate()
+ d.fill = (*compressor).fillDeflate
+ d.step = (*compressor).deflate
default:
return WrongValueError{"level", 0, 9, int32(level)}
}
+ return nil
+}
- if d.sync {
- d.syncChan <- err
- d.sync = false
- }
- if err != nil {
- return err
+func (d *compressor) close() os.Error {
+ d.sync = true
+ d.step(d)
+ if d.err != nil {
+ return d.err
}
if d.w.writeStoredHeader(0, true); d.w.err != nil {
return d.w.err
}
- return d.flush()
+ d.w.flush()
+ return d.w.err
}
// NewWriter returns a new Writer compressing
@@ -486,14 +430,9 @@ func (d *compressor) compress(r io.Reader, w io.Writer, level int, logWindowSize
// 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}
+ var dw Writer
+ dw.d.init(w, level)
+ return &dw
}
// NewWriterDict is like NewWriter but initializes the new
@@ -526,18 +465,13 @@ func (w *dictWriter) Write(b []byte) (n int, err os.Error) {
// 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
+ 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)
+ return w.d.write(data)
}
// Flush flushes any pending compressed data to the underlying writer.
@@ -550,18 +484,10 @@ func (w *Writer) Write(data []byte) (n int, err os.Error) {
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
+ return w.d.syncFlush()
}
// Close flushes and closes the writer.
func (w *Writer) Close() os.Error {
- return w.w.Close()
+ return w.d.close()
}
diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go
index 650a8059ace..930823685f1 100644
--- a/libgo/go/compress/flate/deflate_test.go
+++ b/libgo/go/compress/flate/deflate_test.go
@@ -57,7 +57,7 @@ var deflateInflateTests = []*deflateInflateTest{
&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()},
+ &deflateInflateTest{largeDataChunk()},
}
var reverseBitsTests = []*reverseBitsTest{
@@ -71,23 +71,22 @@ var reverseBitsTests = []*reverseBitsTest{
&reverseBitsTest{29, 5, 23},
}
-func getLargeDataChunk() []byte {
+func largeDataChunk() []byte {
result := make([]byte, 100000)
for i := range result {
- result[i] = byte(int64(i) * int64(i) & 0xFF)
+ result[i] = byte(i * i & 0xFF)
}
return result
}
func TestDeflate(t *testing.T) {
for _, h := range deflateTests {
- buffer := bytes.NewBuffer(nil)
- w := NewWriter(buffer, h.level)
+ var buf bytes.Buffer
+ w := NewWriter(&buf, 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)
+ if !bytes.Equal(buf.Bytes(), h.out) {
+ t.Errorf("Deflate(%d, %x) = %x, want %x", h.level, h.in, buf.Bytes(), h.out)
}
}
}
@@ -226,7 +225,6 @@ func testSync(t *testing.T, level int, input []byte, name string) {
}
}
-
func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os.Error {
buffer := bytes.NewBuffer(nil)
w := NewWriter(buffer, level)
diff --git a/libgo/go/compress/flate/huffman_bit_writer.go b/libgo/go/compress/flate/huffman_bit_writer.go
index abff82dd694..3981df5cba4 100644
--- a/libgo/go/compress/flate/huffman_bit_writer.go
+++ b/libgo/go/compress/flate/huffman_bit_writer.go
@@ -15,9 +15,6 @@ 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
@@ -100,11 +97,11 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
return &huffmanBitWriter{
w: w,
literalFreq: make([]int32, maxLit),
- offsetFreq: make([]int32, extendedOffsetCodeCount),
- codegen: make([]uint8, maxLit+extendedOffsetCodeCount+1),
+ offsetFreq: make([]int32, offsetCodeCount),
+ codegen: make([]uint8, maxLit+offsetCodeCount+1),
codegenFreq: make([]int32, codegenCodeCount),
literalEncoding: newHuffmanEncoder(maxLit),
- offsetEncoding: newHuffmanEncoder(extendedOffsetCodeCount),
+ offsetEncoding: newHuffmanEncoder(offsetCodeCount),
codegenEncoding: newHuffmanEncoder(codegenCodeCount),
}
}
@@ -185,7 +182,7 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
_, w.err = w.w.Write(bytes)
}
-// RFC 1951 3.2.7 specifies a special run-length encoding for specifiying
+// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
// the literal and offset lengths arrays (which are concatenated into a single
// array). This method generates that run-length encoding.
//
@@ -279,7 +276,7 @@ func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) {
//
// numLiterals The number of literals specified in codegen
// numOffsets The number of offsets specified in codegen
-// numCodegens Tne number of codegens used in codegen
+// numCodegens The number of codegens used in codegen
func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) {
if w.err != nil {
return
@@ -290,13 +287,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n
}
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(numOffsets-1), 5)
w.writeBits(int32(numCodegens-4), 4)
for i := 0; i < numCodegens; i++ {
@@ -368,24 +359,17 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
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)
@@ -394,15 +378,25 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
}
// get the number of offsets
numOffsets := len(w.offsetFreq)
- for numOffsets > 1 && w.offsetFreq[numOffsets-1] == 0 {
+ for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 {
numOffsets--
}
+ if numOffsets == 0 {
+ // We haven't found a single match. If we want to go with the dynamic encoding,
+ // we should count at least one offset to be sure that the offset huffman tree could be encoded.
+ w.offsetFreq[0] = 1
+ numOffsets = 1
+ }
+
+ w.literalEncoding.generate(w.literalFreq, 15)
+ w.offsetEncoding.generate(w.offsetFreq, 15)
+
storedBytes := 0
if input != nil {
storedBytes = len(input)
}
var extraBits int64
- var storedSize int64
+ var storedSize int64 = math.MaxInt64
if storedBytes <= maxStoreBlockSize && input != nil {
storedSize = int64((storedBytes + 5) * 8)
// We only bother calculating the costs of the extra bits required by
@@ -417,34 +411,29 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
// 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
- }
+ // Figure out smallest code.
+ // Fixed Huffman baseline.
+ var size = int64(3) +
+ fixedLiteralEncoding.bitLength(w.literalFreq) +
+ fixedOffsetEncoding.bitLength(w.offsetFreq) +
+ extraBits
+ var literalEncoding = fixedLiteralEncoding
+ var offsetEncoding = fixedOffsetEncoding
+
+ // Dynamic Huffman?
+ var numCodegens int
+
// 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)
+ 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) +
@@ -454,26 +443,25 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
w.literalEncoding.bitLength(w.literalFreq) +
w.offsetEncoding.bitLength(w.offsetFreq)
- if storedSize < fixedSize && storedSize < dynamicSize {
+ if dynamicSize < size {
+ size = dynamicSize
+ literalEncoding = w.literalEncoding
+ offsetEncoding = w.offsetEncoding
+ }
+
+ // Stored bytes?
+ if storedSize < size {
w.writeStoredHeader(storedBytes, eof)
w.writeBytes(input[0:storedBytes])
return
}
- var literalEncoding *huffmanEncoder
- var offsetEncoding *huffmanEncoder
- if fixedSize <= dynamicSize {
+ // Huffman.
+ if literalEncoding == fixedLiteralEncoding {
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:
diff --git a/libgo/go/compress/flate/huffman_code.go b/libgo/go/compress/flate/huffman_code.go
index 6be605f0a59..7ed603a4f43 100644
--- a/libgo/go/compress/flate/huffman_code.go
+++ b/libgo/go/compress/flate/huffman_code.go
@@ -363,7 +363,12 @@ func (s literalNodeSorter) Less(i, j int) bool {
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 }}
+ s := &literalNodeSorter{a, func(i, j int) bool {
+ if a[i].freq == a[j].freq {
+ return a[i].literal < a[j].literal
+ }
+ return a[i].freq < a[j].freq
+ }}
sort.Sort(s)
}
diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go
index 320b80d0699..3845f120410 100644
--- a/libgo/go/compress/flate/inflate.go
+++ b/libgo/go/compress/flate/inflate.go
@@ -77,8 +77,6 @@ type huffmanDecoder struct {
// 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
@@ -197,9 +195,8 @@ type Reader interface {
// Decompress state.
type decompressor struct {
- // Input/output sources.
+ // Input source.
r Reader
- w io.Writer
roffset int64
woffset int64
@@ -222,38 +219,79 @@ type decompressor struct {
// Temporary buffer (avoids repeated allocation).
buf [4]byte
+
+ // Next step in the decompression,
+ // and decompression state.
+ step func(*decompressor)
+ final bool
+ err os.Error
+ toRead []byte
+ hl, hd *huffmanDecoder
+ copyLen int
+ copyDist int
}
-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
- }
+func (f *decompressor) nextBlock() {
+ if f.final {
+ if f.hw != f.hp {
+ f.flush((*decompressor).nextBlock)
+ 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)
+ f.err = os.EOF
+ return
+ }
+ for f.nb < 1+2 {
+ if f.err = f.moreBits(); f.err != nil {
+ return
+ }
+ }
+ f.final = f.b&1 == 1
+ f.b >>= 1
+ typ := f.b & 3
+ f.b >>= 2
+ f.nb -= 1 + 2
+ switch typ {
+ case 0:
+ f.dataBlock()
+ case 1:
+ // compressed, fixed Huffman tables
+ f.hl = &fixedHuffmanDecoder
+ f.hd = nil
+ f.huffmanBlock()
+ case 2:
+ // compressed, dynamic Huffman tables
+ if f.err = f.readHuffman(); f.err != nil {
+ break
+ }
+ f.hl = &f.h1
+ f.hd = &f.h2
+ f.huffmanBlock()
+ default:
+ // 3 is reserved.
+ f.err = CorruptInputError(f.roffset)
+ }
+}
+
+func (f *decompressor) Read(b []byte) (int, os.Error) {
+ for {
+ if len(f.toRead) > 0 {
+ n := copy(b, f.toRead)
+ f.toRead = f.toRead[n:]
+ return n, nil
+ }
+ if f.err != nil {
+ return 0, f.err
}
+ f.step(f)
}
- return
+ panic("unreachable")
+}
+
+func (f *decompressor) Close() os.Error {
+ if f.err == os.EOF {
+ return nil
+ }
+ return f.err
}
// RFC 1951 section 3.2.7.
@@ -358,11 +396,12 @@ func (f *decompressor) readHuffman() os.Error {
// 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 {
+func (f *decompressor) huffmanBlock() {
for {
- v, err := f.huffSym(hl)
+ v, err := f.huffSym(f.hl)
if err != nil {
- return err
+ f.err = err
+ return
}
var n uint // number of bits extra
var length int
@@ -371,13 +410,15 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
f.hist[f.hp] = byte(v)
f.hp++
if f.hp == len(f.hist) {
- if err = f.flush(); err != nil {
- return err
- }
+ // After the flush, continue this loop.
+ f.flush((*decompressor).huffmanBlock)
+ return
}
continue
case v == 256:
- return nil
+ // Done with huffman block; read next block.
+ f.step = (*decompressor).nextBlock
+ return
// otherwise, reference to older data
case v < 265:
length = v - (257 - 3)
@@ -404,7 +445,8 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
if n > 0 {
for f.nb < n {
if err = f.moreBits(); err != nil {
- return err
+ f.err = err
+ return
}
}
length += int(f.b & uint32(1<<n-1))
@@ -413,18 +455,20 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
}
var dist int
- if hd == nil {
+ if f.hd == nil {
for f.nb < 5 {
if err = f.moreBits(); err != nil {
- return err
+ f.err = err
+ return
}
}
dist = int(reverseByte[(f.b&0x1F)<<3])
f.b >>= 5
f.nb -= 5
} else {
- if dist, err = f.huffSym(hd); err != nil {
- return err
+ if dist, err = f.huffSym(f.hd); err != nil {
+ f.err = err
+ return
}
}
@@ -432,14 +476,16 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
case dist < 4:
dist++
case dist >= 30:
- return CorruptInputError(f.roffset)
+ f.err = CorruptInputError(f.roffset)
+ return
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
+ f.err = err
+ return
}
}
extra |= int(f.b & uint32(1<<nb-1))
@@ -450,12 +496,14 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
// Copy history[-dist:-dist+length] into output.
if dist > len(f.hist) {
- return InternalError("bad history distance")
+ f.err = InternalError("bad history distance")
+ return
}
// No check on length; encoding can be prescient.
if !f.hfull && dist > f.hp {
- return CorruptInputError(f.roffset)
+ f.err = CorruptInputError(f.roffset)
+ return
}
p := f.hp - dist
@@ -467,9 +515,11 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
f.hp++
p++
if f.hp == len(f.hist) {
- if err = f.flush(); err != nil {
- return err
- }
+ // After flush continue copying out of history.
+ f.copyLen = length - (i + 1)
+ f.copyDist = dist
+ f.flush((*decompressor).copyHuff)
+ return
}
if p == len(f.hist) {
p = 0
@@ -479,8 +529,33 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error {
panic("unreached")
}
+func (f *decompressor) copyHuff() {
+ length := f.copyLen
+ dist := f.copyDist
+ 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) {
+ f.copyLen = length - (i + 1)
+ f.flush((*decompressor).copyHuff)
+ return
+ }
+ if p == len(f.hist) {
+ p = 0
+ }
+ }
+
+ // Continue processing Huffman block.
+ f.huffmanBlock()
+}
+
// Copy a single uncompressed data block from input to output.
-func (f *decompressor) dataBlock() os.Error {
+func (f *decompressor) dataBlock() {
// Uncompressed.
// Discard current half-byte.
f.nb = 0
@@ -490,21 +565,30 @@ func (f *decompressor) dataBlock() os.Error {
nr, err := io.ReadFull(f.r, f.buf[0:4])
f.roffset += int64(nr)
if err != nil {
- return &ReadError{f.roffset, err}
+ f.err = &ReadError{f.roffset, err}
+ return
}
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)
+ f.err = CorruptInputError(f.roffset)
+ return
}
if n == 0 {
// 0-length block means sync
- return f.flush()
+ f.flush((*decompressor).nextBlock)
+ return
}
- // Read len bytes into history,
- // writing as history fills.
+ f.copyLen = n
+ f.copyData()
+}
+
+func (f *decompressor) copyData() {
+ // Read f.dataLen bytes into history,
+ // pausing for reads as history fills.
+ n := f.copyLen
for n > 0 {
m := len(f.hist) - f.hp
if m > n {
@@ -513,17 +597,18 @@ func (f *decompressor) dataBlock() os.Error {
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}
+ f.err = &ReadError{f.roffset, err}
+ return
}
n -= m
f.hp += m
if f.hp == len(f.hist) {
- if err = f.flush(); err != nil {
- return err
- }
+ f.copyLen = n
+ f.flush((*decompressor).copyData)
+ return
}
}
- return nil
+ f.step = (*decompressor).nextBlock
}
func (f *decompressor) setDict(dict []byte) {
@@ -579,17 +664,8 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, os.Error) {
}
// 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}
- }
+func (f *decompressor) flush(step func(*decompressor)) {
+ f.toRead = f.hist[f.hw:f.hp]
f.woffset += int64(f.hp - f.hw)
f.hw = f.hp
if f.hp == len(f.hist) {
@@ -597,7 +673,7 @@ func (f *decompressor) flush() os.Error {
f.hw = 0
f.hfull = true
}
- return nil
+ f.step = step
}
func makeReader(r io.Reader) Reader {
@@ -607,30 +683,15 @@ func makeReader(r io.Reader) Reader {
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
+ f.r = makeReader(r)
+ f.step = (*decompressor).nextBlock
+ return &f
}
// NewReaderDict is like NewReader but initializes the reader
@@ -641,7 +702,7 @@ func NewReader(r io.Reader) io.ReadCloser {
func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
var f decompressor
f.setDict(dict)
- pr, pw := io.Pipe()
- go func() { pw.CloseWithError(f.decompress(r, pw)) }()
- return pr
+ f.r = makeReader(r)
+ f.step = (*decompressor).nextBlock
+ return &f
}
diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go
index b0ddc81d252..6ac9293d771 100644
--- a/libgo/go/compress/gzip/gunzip.go
+++ b/libgo/go/compress/gzip/gunzip.go
@@ -36,8 +36,8 @@ func makeReader(r io.Reader) flate.Reader {
return bufio.NewReader(r)
}
-var HeaderError os.Error = os.ErrorString("invalid gzip header")
-var ChecksumError os.Error = os.ErrorString("gzip checksum error")
+var HeaderError = os.NewError("invalid gzip header")
+var ChecksumError = os.NewError("gzip checksum error")
// The gzip file stores a header giving metadata about the compressed file.
// That header is exposed as the fields of the Compressor and Decompressor structs.
diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go
index 23f35140556..121e627e6b2 100644
--- a/libgo/go/compress/gzip/gzip_test.go
+++ b/libgo/go/compress/gzip/gzip_test.go
@@ -11,7 +11,7 @@ import (
)
// pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the
-// writer end and ifunc at the reader end.
+// writer end and cfunc at the reader end.
func pipe(t *testing.T, dfunc func(*Compressor), cfunc func(*Decompressor)) {
piper, pipew := io.Pipe()
defer piper.Close()
diff --git a/libgo/go/compress/lzw/reader.go b/libgo/go/compress/lzw/reader.go
index a1cd2abc043..21231c8e519 100644
--- a/libgo/go/compress/lzw/reader.go
+++ b/libgo/go/compress/lzw/reader.go
@@ -32,13 +32,49 @@ const (
MSB
)
+const (
+ maxWidth = 12
+ decoderInvalidCode = 0xffff
+ flushBuffer = 1 << maxWidth
+)
+
// decoder is the state from which the readXxx method converts a byte
// stream into a code stream.
type decoder struct {
- r io.ByteReader
- bits uint32
- nBits uint
- width uint
+ r io.ByteReader
+ bits uint32
+ nBits uint
+ width uint
+ read func(*decoder) (uint16, os.Error) // readLSB or readMSB
+ litWidth int // width in bits of literal codes
+ err os.Error
+
+ // The first 1<<litWidth codes are literal codes.
+ // The next two codes mean clear and EOF.
+ // Other valid codes are in the range [lo, hi] where lo := clear + 2,
+ // with the upper bound incrementing on each code seen.
+ // overflow is the code at which hi overflows the code width.
+ // last is the most recently seen code, or decoderInvalidCode.
+ clear, eof, hi, overflow, last uint16
+
+ // Each code c in [lo, hi] expands to two or more bytes. For c != hi:
+ // suffix[c] is the last of these bytes.
+ // prefix[c] is the code for all but the last byte.
+ // This code can either be a literal code or another code in [lo, c).
+ // The c == hi case is a special case.
+ suffix [1 << maxWidth]uint8
+ prefix [1 << maxWidth]uint16
+
+ // output is the temporary output buffer.
+ // Literal codes are accumulated from the start of the buffer.
+ // Non-literal codes decode to a sequence of suffixes that are first
+ // written right-to-left from the end of the buffer before being copied
+ // to the start of the buffer.
+ // It is flushed when it contains >= 1<<maxWidth bytes,
+ // so that there is always room to decode an entire code.
+ output [2 * 1 << maxWidth]byte
+ o int // write index into output
+ toRead []byte // bytes to return from Read
}
// readLSB returns the next code for "Least Significant Bits first" data.
@@ -73,119 +109,113 @@ func (d *decoder) readMSB() (uint16, os.Error) {
return code, nil
}
-// decode decompresses bytes from r and writes them to pw.
-// read specifies how to decode bytes into codes.
-// litWidth is the width in bits of literal codes.
-func decode(r io.Reader, read func(*decoder) (uint16, os.Error), litWidth int, pw *io.PipeWriter) {
- br, ok := r.(io.ByteReader)
- if !ok {
- br = bufio.NewReader(r)
+func (d *decoder) Read(b []byte) (int, os.Error) {
+ for {
+ if len(d.toRead) > 0 {
+ n := copy(b, d.toRead)
+ d.toRead = d.toRead[n:]
+ return n, nil
+ }
+ if d.err != nil {
+ return 0, d.err
+ }
+ d.decode()
}
- pw.CloseWithError(decode1(pw, br, read, uint(litWidth)))
+ panic("unreachable")
}
-func decode1(pw *io.PipeWriter, r io.ByteReader, read func(*decoder) (uint16, os.Error), litWidth uint) os.Error {
- const (
- maxWidth = 12
- invalidCode = 0xffff
- )
- d := decoder{r, 0, 0, 1 + litWidth}
- w := bufio.NewWriter(pw)
- // The first 1<<litWidth codes are literal codes.
- // The next two codes mean clear and EOF.
- // Other valid codes are in the range [lo, hi] where lo := clear + 2,
- // with the upper bound incrementing on each code seen.
- clear := uint16(1) << litWidth
- eof, hi := clear+1, clear+1
- // overflow is the code at which hi overflows the code width.
- overflow := uint16(1) << d.width
- var (
- // Each code c in [lo, hi] expands to two or more bytes. For c != hi:
- // suffix[c] is the last of these bytes.
- // prefix[c] is the code for all but the last byte.
- // This code can either be a literal code or another code in [lo, c).
- // The c == hi case is a special case.
- suffix [1 << maxWidth]uint8
- prefix [1 << maxWidth]uint16
- // buf is a scratch buffer for reconstituting the bytes that a code expands to.
- // Code suffixes are written right-to-left from the end of the buffer.
- buf [1 << maxWidth]byte
- )
-
+// decode decompresses bytes from r and leaves them in d.toRead.
+// read specifies how to decode bytes into codes.
+// litWidth is the width in bits of literal codes.
+func (d *decoder) decode() {
// Loop over the code stream, converting codes into decompressed bytes.
- last := uint16(invalidCode)
for {
- code, err := read(&d)
+ code, err := d.read(d)
if err != nil {
if err == os.EOF {
err = io.ErrUnexpectedEOF
}
- return err
+ d.err = err
+ return
}
switch {
- case code < clear:
+ case code < d.clear:
// We have a literal code.
- if err := w.WriteByte(uint8(code)); err != nil {
- return err
- }
- if last != invalidCode {
+ d.output[d.o] = uint8(code)
+ d.o++
+ if d.last != decoderInvalidCode {
// Save what the hi code expands to.
- suffix[hi] = uint8(code)
- prefix[hi] = last
+ d.suffix[d.hi] = uint8(code)
+ d.prefix[d.hi] = d.last
}
- case code == clear:
- d.width = 1 + litWidth
- hi = eof
- overflow = 1 << d.width
- last = invalidCode
+ case code == d.clear:
+ d.width = 1 + uint(d.litWidth)
+ d.hi = d.eof
+ d.overflow = 1 << d.width
+ d.last = decoderInvalidCode
continue
- case code == eof:
- return w.Flush()
- case code <= hi:
- c, i := code, len(buf)-1
- if code == hi {
+ case code == d.eof:
+ d.flush()
+ d.err = os.EOF
+ return
+ case code <= d.hi:
+ c, i := code, len(d.output)-1
+ if code == d.hi {
// code == hi is a special case which expands to the last expansion
// followed by the head of the last expansion. To find the head, we walk
// the prefix chain until we find a literal code.
- c = last
- for c >= clear {
- c = prefix[c]
+ c = d.last
+ for c >= d.clear {
+ c = d.prefix[c]
}
- buf[i] = uint8(c)
+ d.output[i] = uint8(c)
i--
- c = last
+ c = d.last
}
- // Copy the suffix chain into buf and then write that to w.
- for c >= clear {
- buf[i] = suffix[c]
+ // Copy the suffix chain into output and then write that to w.
+ for c >= d.clear {
+ d.output[i] = d.suffix[c]
i--
- c = prefix[c]
+ c = d.prefix[c]
}
- buf[i] = uint8(c)
- if _, err := w.Write(buf[i:]); err != nil {
- return err
- }
- if last != invalidCode {
+ d.output[i] = uint8(c)
+ d.o += copy(d.output[d.o:], d.output[i:])
+ if d.last != decoderInvalidCode {
// Save what the hi code expands to.
- suffix[hi] = uint8(c)
- prefix[hi] = last
+ d.suffix[d.hi] = uint8(c)
+ d.prefix[d.hi] = d.last
}
default:
- return os.NewError("lzw: invalid code")
+ d.err = os.NewError("lzw: invalid code")
+ return
}
- last, hi = code, hi+1
- if hi >= overflow {
+ d.last, d.hi = code, d.hi+1
+ if d.hi >= d.overflow {
if d.width == maxWidth {
- last = invalidCode
- continue
+ d.last = decoderInvalidCode
+ } else {
+ d.width++
+ d.overflow <<= 1
}
- d.width++
- overflow <<= 1
+ }
+ if d.o >= flushBuffer {
+ d.flush()
+ return
}
}
panic("unreachable")
}
+func (d *decoder) flush() {
+ d.toRead = d.output[:d.o]
+ d.o = 0
+}
+
+func (d *decoder) Close() os.Error {
+ d.err = os.EINVAL // in case any Reads come along
+ return nil
+}
+
// NewReader creates a new io.ReadCloser that satisfies reads by decompressing
// the data read from r.
// It is the caller's responsibility to call Close on the ReadCloser when
@@ -193,21 +223,31 @@ func decode1(pw *io.PipeWriter, r io.ByteReader, read func(*decoder) (uint16, os
// The number of bits to use for literal codes, litWidth, must be in the
// range [2,8] and is typically 8.
func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
- pr, pw := io.Pipe()
- var read func(*decoder) (uint16, os.Error)
+ d := new(decoder)
switch order {
case LSB:
- read = (*decoder).readLSB
+ d.read = (*decoder).readLSB
case MSB:
- read = (*decoder).readMSB
+ d.read = (*decoder).readMSB
default:
- pw.CloseWithError(os.NewError("lzw: unknown order"))
- return pr
+ d.err = os.NewError("lzw: unknown order")
+ return d
}
if litWidth < 2 || 8 < litWidth {
- pw.CloseWithError(fmt.Errorf("lzw: litWidth %d out of range", litWidth))
- return pr
+ d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth)
+ return d
}
- go decode(r, read, litWidth, pw)
- return pr
+ if br, ok := r.(io.ByteReader); ok {
+ d.r = br
+ } else {
+ d.r = bufio.NewReader(r)
+ }
+ d.litWidth = litWidth
+ d.width = 1 + uint(litWidth)
+ d.clear = uint16(1) << uint(litWidth)
+ d.eof, d.hi = d.clear+1, d.clear+1
+ d.overflow = uint16(1) << d.width
+ d.last = decoderInvalidCode
+
+ return d
}
diff --git a/libgo/go/compress/lzw/reader_test.go b/libgo/go/compress/lzw/reader_test.go
index 72121a6b569..f8042b0d191 100644
--- a/libgo/go/compress/lzw/reader_test.go
+++ b/libgo/go/compress/lzw/reader_test.go
@@ -84,7 +84,7 @@ var lzwTests = []lzwTest{
func TestReader(t *testing.T) {
b := bytes.NewBuffer(nil)
for _, tt := range lzwTests {
- d := strings.Split(tt.desc, ";", -1)
+ d := strings.Split(tt.desc, ";")
var order Order
switch d[1] {
case "LSB":
diff --git a/libgo/go/compress/lzw/writer_test.go b/libgo/go/compress/lzw/writer_test.go
index 82464ecd1b0..4c5e522f943 100644
--- a/libgo/go/compress/lzw/writer_test.go
+++ b/libgo/go/compress/lzw/writer_test.go
@@ -77,13 +77,13 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1)
return
}
- if len(b0) != len(b1) {
- t.Errorf("%s (order=%d litWidth=%d): length mismatch %d versus %d", fn, order, litWidth, len(b0), len(b1))
+ if len(b1) != len(b0) {
+ t.Errorf("%s (order=%d litWidth=%d): length mismatch %d != %d", fn, order, litWidth, len(b1), len(b0))
return
}
for i := 0; i < len(b0); i++ {
- if b0[i] != b1[i] {
- t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x versus 0x%02x\n", fn, order, litWidth, i, b0[i], b1[i])
+ if b1[i] != b0[i] {
+ t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x != 0x%02x\n", fn, order, litWidth, i, b1[i], b0[i])
return
}
}
diff --git a/libgo/go/compress/zlib/reader.go b/libgo/go/compress/zlib/reader.go
index 8a3ef1580aa..78dabdf4d8c 100644
--- a/libgo/go/compress/zlib/reader.go
+++ b/libgo/go/compress/zlib/reader.go
@@ -34,9 +34,9 @@ import (
const zlibDeflate = 8
-var ChecksumError os.Error = os.ErrorString("zlib checksum error")
-var HeaderError os.Error = os.ErrorString("invalid zlib header")
-var DictionaryError os.Error = os.ErrorString("invalid zlib dictionary")
+var ChecksumError = os.NewError("zlib checksum error")
+var HeaderError = os.NewError("invalid zlib header")
+var DictionaryError = os.NewError("invalid zlib dictionary")
type reader struct {
r flate.Reader
diff --git a/libgo/go/compress/zlib/writer.go b/libgo/go/compress/zlib/writer.go
index f1f9b285375..8f86e9c4ce3 100644
--- a/libgo/go/compress/zlib/writer.go
+++ b/libgo/go/compress/zlib/writer.go
@@ -89,7 +89,7 @@ func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, os.Error) {
}
}
z.w = w
- z.compressor = flate.NewWriter(w, level)
+ z.compressor = flate.NewWriterDict(w, level, dict)
z.digest = adler32.New()
return z, nil
}
diff --git a/libgo/go/compress/zlib/writer_test.go b/libgo/go/compress/zlib/writer_test.go
index f94f2847006..32f05ab6856 100644
--- a/libgo/go/compress/zlib/writer_test.go
+++ b/libgo/go/compress/zlib/writer_test.go
@@ -5,6 +5,8 @@
package zlib
import (
+ "bytes"
+ "fmt"
"io"
"io/ioutil"
"os"
@@ -16,15 +18,13 @@ var filenames = []string{
"../testdata/pi.txt",
}
+var data = []string{
+ "test a reasonable sized string that can be compressed",
+}
+
// Tests that compressing and then decompressing the given file at the given compression level and dictionary
// yields equivalent bytes to the original file.
func testFileLevelDict(t *testing.T, fn string, level int, d string) {
- // Read dictionary, if given.
- var dict []byte
- if d != "" {
- dict = []byte(d)
- }
-
// Read the file, as golden output.
golden, err := os.Open(fn)
if err != nil {
@@ -32,17 +32,25 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) {
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)
- if err != nil {
- t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
+ b0, err0 := ioutil.ReadAll(golden)
+ if err0 != nil {
+ t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err0)
return
}
+ testLevelDict(t, fn, b0, level, d)
+}
+
+func testLevelDict(t *testing.T, fn string, b0 []byte, level int, d string) {
+ // Make dictionary, if given.
+ var dict []byte
+ if d != "" {
+ dict = []byte(d)
+ }
+
+ // Push data through a pipe that compresses at the write end, and decompresses at the read end.
piper, pipew := io.Pipe()
defer piper.Close()
go func() {
- defer raw.Close()
defer pipew.Close()
zlibw, err := NewWriterDict(pipew, level, dict)
if err != nil {
@@ -50,25 +58,14 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) {
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, dict=%q): %v", fn, level, d, 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, dict=%q): %v", fn, level, d, err1)
- return
- }
- if err0 == os.EOF {
- break
- }
+ _, err = zlibw.Write(b0)
+ if err == os.EPIPE {
+ // Fail, but do not report the error, as some other (presumably reported) error broke the pipe.
+ return
+ }
+ if err != nil {
+ t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
+ return
}
}()
zlibr, err := NewReaderDict(piper, dict)
@@ -78,13 +75,8 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) {
}
defer zlibr.Close()
- // Compare the two.
- b0, err0 := ioutil.ReadAll(golden)
+ // Compare the decompressed data.
b1, err1 := ioutil.ReadAll(zlibr)
- if err0 != nil {
- t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err0)
- return
- }
if err1 != nil {
t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err1)
return
@@ -102,6 +94,18 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) {
}
func TestWriter(t *testing.T) {
+ for i, s := range data {
+ b := []byte(s)
+ tag := fmt.Sprintf("#%d", i)
+ testLevelDict(t, tag, b, DefaultCompression, "")
+ testLevelDict(t, tag, b, NoCompression, "")
+ for level := BestSpeed; level <= BestCompression; level++ {
+ testLevelDict(t, tag, b, level, "")
+ }
+ }
+}
+
+func TestWriterBig(t *testing.T) {
for _, fn := range filenames {
testFileLevelDict(t, fn, DefaultCompression, "")
testFileLevelDict(t, fn, NoCompression, "")
@@ -121,3 +125,20 @@ func TestWriterDict(t *testing.T) {
}
}
}
+
+func TestWriterDictIsUsed(t *testing.T) {
+ var input = []byte("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
+ buf := bytes.NewBuffer(nil)
+ compressor, err := NewWriterDict(buf, BestCompression, input)
+ if err != nil {
+ t.Errorf("error in NewWriterDict: %s", err)
+ return
+ }
+ compressor.Write(input)
+ compressor.Close()
+ const expectedMaxSize = 25
+ output := buf.Bytes()
+ if len(output) > expectedMaxSize {
+ t.Errorf("result too large (got %d, want <= %d bytes). Is the dictionary being used?", len(output), expectedMaxSize)
+ }
+}
diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go
index f2b8a750a45..2dfe5b43ca7 100644
--- a/libgo/go/container/heap/heap.go
+++ b/libgo/go/container/heap/heap.go
@@ -21,8 +21,7 @@ type Interface interface {
Pop() interface{}
}
-
-// A heaper must be initialized before any of the heap operations
+// A heap 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().
@@ -35,7 +34,6 @@ func Init(h Interface) {
}
}
-
// Push pushes the element x onto the heap. The complexity is
// O(log(n)) where n = h.Len().
//
@@ -44,7 +42,6 @@ func Push(h Interface, x interface{}) {
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).
@@ -56,7 +53,6 @@ func Pop(h Interface) interface{} {
return h.Pop()
}
-
// Remove removes the element at index i from the heap.
// The complexity is O(log(n)) where n = h.Len().
//
@@ -70,7 +66,6 @@ func Remove(h Interface, i int) interface{} {
return h.Pop()
}
-
func up(h Interface, j int) {
for {
i := (j - 1) / 2 // parent
@@ -82,7 +77,6 @@ func up(h Interface, j int) {
}
}
-
func down(h Interface, i, n int) {
for {
j1 := 2*i + 1
diff --git a/libgo/go/container/heap/heap_test.go b/libgo/go/container/heap/heap_test.go
index 5eb54374ab2..c5c1f76e1e1 100644
--- a/libgo/go/container/heap/heap_test.go
+++ b/libgo/go/container/heap/heap_test.go
@@ -10,17 +10,14 @@ import (
. "container/heap"
)
-
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
@@ -41,7 +38,6 @@ func (h *myHeap) verify(t *testing.T, i int) {
}
}
-
func TestInit0(t *testing.T) {
h := new(myHeap)
for i := 20; i > 0; i-- {
@@ -59,7 +55,6 @@ func TestInit0(t *testing.T) {
}
}
-
func TestInit1(t *testing.T) {
h := new(myHeap)
for i := 20; i > 0; i-- {
@@ -77,7 +72,6 @@ func TestInit1(t *testing.T) {
}
}
-
func Test(t *testing.T) {
h := new(myHeap)
h.verify(t, 0)
@@ -105,7 +99,6 @@ func Test(t *testing.T) {
}
}
-
func TestRemove0(t *testing.T) {
h := new(myHeap)
for i := 0; i < 10; i++ {
@@ -123,7 +116,6 @@ func TestRemove0(t *testing.T) {
}
}
-
func TestRemove1(t *testing.T) {
h := new(myHeap)
for i := 0; i < 10; i++ {
@@ -140,7 +132,6 @@ func TestRemove1(t *testing.T) {
}
}
-
func TestRemove2(t *testing.T) {
N := 10
diff --git a/libgo/go/container/ring/ring.go b/libgo/go/container/ring/ring.go
index cc870ce9364..1d96918d37b 100644
--- a/libgo/go/container/ring/ring.go
+++ b/libgo/go/container/ring/ring.go
@@ -16,14 +16,12 @@ type Ring struct {
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 {
@@ -32,7 +30,6 @@ func (r *Ring) Next() *Ring {
return r.next
}
-
// Prev returns the previous ring element. r must not be empty.
func (r *Ring) Prev() *Ring {
if r.next == nil {
@@ -41,7 +38,6 @@ func (r *Ring) Prev() *Ring {
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.
//
@@ -62,7 +58,6 @@ func (r *Ring) Move(n int) *Ring {
return r
}
-
// New creates a ring of n elements.
func New(n int) *Ring {
if n <= 0 {
@@ -79,7 +74,6 @@ func New(n int) *Ring {
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.
@@ -110,7 +104,6 @@ func (r *Ring) Link(s *Ring) *Ring {
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.
@@ -122,7 +115,6 @@ func (r *Ring) Unlink(n int) *Ring {
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.
//
@@ -137,7 +129,6 @@ func (r *Ring) Len() int {
return n
}
-
// Do calls function f on each element of the ring, in forward order.
// The behavior of Do is undefined if f changes *r.
func (r *Ring) Do(f func(interface{})) {
diff --git a/libgo/go/container/ring/ring_test.go b/libgo/go/container/ring/ring_test.go
index 778c083d02b..099d92b25b2 100644
--- a/libgo/go/container/ring/ring_test.go
+++ b/libgo/go/container/ring/ring_test.go
@@ -9,7 +9,6 @@ import (
"testing"
)
-
// For debugging - keep around.
func dump(r *Ring) {
if r == nil {
@@ -24,7 +23,6 @@ func dump(r *Ring) {
fmt.Println()
}
-
func verify(t *testing.T, r *Ring, N int, sum int) {
// Len
n := r.Len()
@@ -96,7 +94,6 @@ func verify(t *testing.T, r *Ring, N int, sum int) {
}
}
-
func TestCornerCases(t *testing.T) {
var (
r0 *Ring
@@ -118,7 +115,6 @@ func TestCornerCases(t *testing.T) {
verify(t, &r1, 1, 0)
}
-
func makeN(n int) *Ring {
r := New(n)
for i := 1; i <= n; i++ {
@@ -130,7 +126,6 @@ func makeN(n int) *Ring {
func sumN(n int) int { return (n*n + n) / 2 }
-
func TestNew(t *testing.T) {
for i := 0; i < 10; i++ {
r := New(i)
@@ -142,7 +137,6 @@ func TestNew(t *testing.T) {
}
}
-
func TestLink1(t *testing.T) {
r1a := makeN(1)
var r1b Ring
@@ -163,7 +157,6 @@ func TestLink1(t *testing.T) {
verify(t, r2b, 1, 0)
}
-
func TestLink2(t *testing.T) {
var r0 *Ring
r1a := &Ring{Value: 42}
@@ -183,7 +176,6 @@ func TestLink2(t *testing.T) {
verify(t, r10, 12, sumN(10)+42+77)
}
-
func TestLink3(t *testing.T) {
var r Ring
n := 1
@@ -193,7 +185,6 @@ func TestLink3(t *testing.T) {
}
}
-
func TestUnlink(t *testing.T) {
r10 := makeN(10)
s10 := r10.Move(6)
@@ -215,7 +206,6 @@ func TestUnlink(t *testing.T) {
verify(t, r10, 9, sum10-2)
}
-
func TestLinkUnlink(t *testing.T) {
for i := 1; i < 4; i++ {
ri := New(i)
diff --git a/libgo/go/container/vector/defs.go b/libgo/go/container/vector/defs.go
index bfb5481fb89..6d6b2ac81a3 100644
--- a/libgo/go/container/vector/defs.go
+++ b/libgo/go/container/vector/defs.go
@@ -6,29 +6,24 @@
// 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.
@@ -36,16 +31,13 @@ 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
index 5ad9e294b75..aa88cfeb367 100644
--- a/libgo/go/container/vector/intvector.go
+++ b/libgo/go/container/vector/intvector.go
@@ -7,7 +7,6 @@
package vector
-
func (p *IntVector) realloc(length, capacity int) (b []int) {
if capacity < initialSize {
capacity = initialSize
@@ -21,7 +20,6 @@ func (p *IntVector) realloc(length, capacity int) (b []int) {
return
}
-
// Insert n elements at position i.
func (p *IntVector) Expand(i, n int) {
a := *p
@@ -51,11 +49,9 @@ func (p *IntVector) Expand(i, n int) {
*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,
@@ -80,30 +76,24 @@ func (p *IntVector) Resize(length, capacity int) *IntVector {
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))
@@ -111,7 +101,6 @@ func (p *IntVector) Copy() IntVector {
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) {
@@ -119,7 +108,6 @@ func (p *IntVector) Insert(i int, x int) {
(*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) {
@@ -132,7 +120,6 @@ func (p *IntVector) Delete(i int) {
*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) {
@@ -142,7 +129,6 @@ func (p *IntVector) InsertVector(i int, x *IntVector) {
copy((*p)[i:i+len(b)], b)
}
-
// Cut deletes elements i through j-1, inclusive.
func (p *IntVector) Cut(i, j int) {
a := *p
@@ -158,7 +144,6 @@ func (p *IntVector) Cut(i, j int) {
*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 {
@@ -168,13 +153,11 @@ func (p *IntVector) Slice(i, j int) *IntVector {
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
@@ -187,18 +170,15 @@ func (p *IntVector) Pop() int {
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)) {
diff --git a/libgo/go/container/vector/intvector_test.go b/libgo/go/container/vector/intvector_test.go
index 1e38a1982f6..b825af91221 100644
--- a/libgo/go/container/vector/intvector_test.go
+++ b/libgo/go/container/vector/intvector_test.go
@@ -9,7 +9,6 @@ package vector
import "testing"
-
func TestIntZeroLen(t *testing.T) {
a := new(IntVector)
if a.Len() != 0 {
@@ -27,7 +26,6 @@ func TestIntZeroLen(t *testing.T) {
}
}
-
func TestIntResize(t *testing.T) {
var a IntVector
checkSize(t, &a, 0, 0)
@@ -40,7 +38,6 @@ func TestIntResize(t *testing.T) {
checkSize(t, a.Resize(11, 100), 11, 100)
}
-
func TestIntResize2(t *testing.T) {
var a IntVector
checkSize(t, &a, 0, 0)
@@ -62,7 +59,6 @@ func TestIntResize2(t *testing.T) {
}
}
-
func checkIntZero(t *testing.T, a *IntVector, i int) {
for j := 0; j < i; j++ {
if a.At(j) == intzero {
@@ -82,7 +78,6 @@ func checkIntZero(t *testing.T, a *IntVector, i int) {
}
}
-
func TestIntTrailingElements(t *testing.T) {
var a IntVector
for i := 0; i < 10; i++ {
@@ -95,7 +90,6 @@ func TestIntTrailingElements(t *testing.T) {
checkIntZero(t, &a, 5)
}
-
func TestIntAccess(t *testing.T) {
const n = 100
var a IntVector
@@ -120,7 +114,6 @@ func TestIntAccess(t *testing.T) {
}
}
-
func TestIntInsertDeleteClear(t *testing.T) {
const n = 100
var a IntVector
@@ -207,7 +200,6 @@ func TestIntInsertDeleteClear(t *testing.T) {
}
}
-
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) {
@@ -223,7 +215,6 @@ func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
}
}
-
func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
n := a + b + c
if x.Len() != n {
@@ -237,7 +228,6 @@ func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
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++ {
@@ -246,7 +236,6 @@ func make_vectorInt(elt, len int) *IntVector {
return x
}
-
func TestIntInsertVector(t *testing.T) {
// 1
a := make_vectorInt(0, 0)
@@ -270,7 +259,6 @@ func TestIntInsertVector(t *testing.T) {
verify_patternInt(t, a, 8, 1000, 2)
}
-
func TestIntDo(t *testing.T) {
const n = 25
const salt = 17
@@ -325,7 +313,6 @@ func TestIntDo(t *testing.T) {
}
-
func TestIntVectorCopy(t *testing.T) {
// verify Copy() returns a copy, not simply a slice of the original vector
const Len = 10
diff --git a/libgo/go/container/vector/nogen_test.go b/libgo/go/container/vector/nogen_test.go
index 790d3749fc2..7b6a25952b1 100644
--- a/libgo/go/container/vector/nogen_test.go
+++ b/libgo/go/container/vector/nogen_test.go
@@ -4,7 +4,6 @@
package vector
-
import (
"fmt"
"sort"
@@ -17,28 +16,23 @@ var (
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())
@@ -48,10 +42,8 @@ func checkSize(t *testing.T, v VectorInterface, len, cap int) {
}
}
-
func val(i int) int { return i*991 - 1234 }
-
func TestSorting(t *testing.T) {
const n = 100
@@ -72,5 +64,4 @@ func TestSorting(t *testing.T) {
}
}
-
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
index b83b0bfeeff..abe01a8fb18 100644
--- a/libgo/go/container/vector/numbers_test.go
+++ b/libgo/go/container/vector/numbers_test.go
@@ -11,10 +11,8 @@ import (
"testing"
)
-
const memTestN = 1000000
-
func s(n uint64) string {
str := fmt.Sprintf("%d", n)
lens := len(str)
@@ -31,7 +29,6 @@ func s(n uint64) string {
return strings.Join(a, " ")
}
-
func TestVectorNums(t *testing.T) {
if testing.Short() {
return
@@ -52,7 +49,6 @@ func TestVectorNums(t *testing.T) {
t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
}
-
func TestIntVectorNums(t *testing.T) {
if testing.Short() {
return
@@ -73,7 +69,6 @@ func TestIntVectorNums(t *testing.T) {
t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN)
}
-
func TestStringVectorNums(t *testing.T) {
if testing.Short() {
return
@@ -94,7 +89,6 @@ func TestStringVectorNums(t *testing.T) {
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
@@ -106,7 +100,6 @@ func BenchmarkVectorNums(b *testing.B) {
}
}
-
func BenchmarkIntVectorNums(b *testing.B) {
c := int(0)
var v IntVector
@@ -118,7 +111,6 @@ func BenchmarkIntVectorNums(b *testing.B) {
}
}
-
func BenchmarkStringVectorNums(b *testing.B) {
c := ""
var v StringVector
diff --git a/libgo/go/container/vector/stringvector.go b/libgo/go/container/vector/stringvector.go
index 852685f5a12..dc81f06b74d 100644
--- a/libgo/go/container/vector/stringvector.go
+++ b/libgo/go/container/vector/stringvector.go
@@ -7,7 +7,6 @@
package vector
-
func (p *StringVector) realloc(length, capacity int) (b []string) {
if capacity < initialSize {
capacity = initialSize
@@ -21,7 +20,6 @@ func (p *StringVector) realloc(length, capacity int) (b []string) {
return
}
-
// Insert n elements at position i.
func (p *StringVector) Expand(i, n int) {
a := *p
@@ -51,11 +49,9 @@ func (p *StringVector) Expand(i, n int) {
*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,
@@ -80,30 +76,24 @@ func (p *StringVector) Resize(length, capacity int) *StringVector {
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))
@@ -111,7 +101,6 @@ func (p *StringVector) Copy() StringVector {
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) {
@@ -119,7 +108,6 @@ func (p *StringVector) Insert(i int, x string) {
(*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) {
@@ -132,7 +120,6 @@ func (p *StringVector) Delete(i int) {
*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) {
@@ -142,7 +129,6 @@ func (p *StringVector) InsertVector(i int, x *StringVector) {
copy((*p)[i:i+len(b)], b)
}
-
// Cut deletes elements i through j-1, inclusive.
func (p *StringVector) Cut(i, j int) {
a := *p
@@ -158,7 +144,6 @@ func (p *StringVector) Cut(i, j int) {
*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 {
@@ -168,13 +153,11 @@ func (p *StringVector) Slice(i, j int) *StringVector {
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
@@ -187,18 +170,15 @@ func (p *StringVector) Pop() string {
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)) {
diff --git a/libgo/go/container/vector/stringvector_test.go b/libgo/go/container/vector/stringvector_test.go
index 776ae26dea1..c75676f786c 100644
--- a/libgo/go/container/vector/stringvector_test.go
+++ b/libgo/go/container/vector/stringvector_test.go
@@ -9,7 +9,6 @@ package vector
import "testing"
-
func TestStrZeroLen(t *testing.T) {
a := new(StringVector)
if a.Len() != 0 {
@@ -27,7 +26,6 @@ func TestStrZeroLen(t *testing.T) {
}
}
-
func TestStrResize(t *testing.T) {
var a StringVector
checkSize(t, &a, 0, 0)
@@ -40,7 +38,6 @@ func TestStrResize(t *testing.T) {
checkSize(t, a.Resize(11, 100), 11, 100)
}
-
func TestStrResize2(t *testing.T) {
var a StringVector
checkSize(t, &a, 0, 0)
@@ -62,7 +59,6 @@ func TestStrResize2(t *testing.T) {
}
}
-
func checkStrZero(t *testing.T, a *StringVector, i int) {
for j := 0; j < i; j++ {
if a.At(j) == strzero {
@@ -82,7 +78,6 @@ func checkStrZero(t *testing.T, a *StringVector, i int) {
}
}
-
func TestStrTrailingElements(t *testing.T) {
var a StringVector
for i := 0; i < 10; i++ {
@@ -95,7 +90,6 @@ func TestStrTrailingElements(t *testing.T) {
checkStrZero(t, &a, 5)
}
-
func TestStrAccess(t *testing.T) {
const n = 100
var a StringVector
@@ -120,7 +114,6 @@ func TestStrAccess(t *testing.T) {
}
}
-
func TestStrInsertDeleteClear(t *testing.T) {
const n = 100
var a StringVector
@@ -207,7 +200,6 @@ func TestStrInsertDeleteClear(t *testing.T) {
}
}
-
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) {
@@ -223,7 +215,6 @@ func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
}
}
-
func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
n := a + b + c
if x.Len() != n {
@@ -237,7 +228,6 @@ func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
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++ {
@@ -246,7 +236,6 @@ func make_vectorStr(elt, len int) *StringVector {
return x
}
-
func TestStrInsertVector(t *testing.T) {
// 1
a := make_vectorStr(0, 0)
@@ -270,7 +259,6 @@ func TestStrInsertVector(t *testing.T) {
verify_patternStr(t, a, 8, 1000, 2)
}
-
func TestStrDo(t *testing.T) {
const n = 25
const salt = 17
@@ -325,7 +313,6 @@ func TestStrDo(t *testing.T) {
}
-
func TestStrVectorCopy(t *testing.T) {
// verify Copy() returns a copy, not simply a slice of the original vector
const Len = 10
diff --git a/libgo/go/container/vector/vector.go b/libgo/go/container/vector/vector.go
index f43e4d23ca2..8470ec067ac 100644
--- a/libgo/go/container/vector/vector.go
+++ b/libgo/go/container/vector/vector.go
@@ -7,7 +7,6 @@
package vector
-
func (p *Vector) realloc(length, capacity int) (b []interface{}) {
if capacity < initialSize {
capacity = initialSize
@@ -21,7 +20,6 @@ func (p *Vector) realloc(length, capacity int) (b []interface{}) {
return
}
-
// Insert n elements at position i.
func (p *Vector) Expand(i, n int) {
a := *p
@@ -51,11 +49,9 @@ func (p *Vector) Expand(i, n int) {
*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,
@@ -80,30 +76,24 @@ func (p *Vector) Resize(length, capacity int) *Vector {
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))
@@ -111,7 +101,6 @@ func (p *Vector) Copy() Vector {
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{}) {
@@ -119,7 +108,6 @@ func (p *Vector) Insert(i int, x interface{}) {
(*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) {
@@ -132,7 +120,6 @@ func (p *Vector) Delete(i int) {
*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) {
@@ -142,7 +129,6 @@ func (p *Vector) InsertVector(i int, x *Vector) {
copy((*p)[i:i+len(b)], b)
}
-
// Cut deletes elements i through j-1, inclusive.
func (p *Vector) Cut(i, j int) {
a := *p
@@ -158,7 +144,6 @@ func (p *Vector) Cut(i, j int) {
*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 {
@@ -168,13 +153,11 @@ func (p *Vector) Slice(i, j int) *Vector {
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
@@ -187,18 +170,15 @@ func (p *Vector) Pop() interface{} {
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{})) {
diff --git a/libgo/go/container/vector/vector_test.go b/libgo/go/container/vector/vector_test.go
index a9c4ceb55ac..a7f47b8c2a5 100644
--- a/libgo/go/container/vector/vector_test.go
+++ b/libgo/go/container/vector/vector_test.go
@@ -9,7 +9,6 @@ package vector
import "testing"
-
func TestZeroLen(t *testing.T) {
a := new(Vector)
if a.Len() != 0 {
@@ -27,7 +26,6 @@ func TestZeroLen(t *testing.T) {
}
}
-
func TestResize(t *testing.T) {
var a Vector
checkSize(t, &a, 0, 0)
@@ -40,7 +38,6 @@ func TestResize(t *testing.T) {
checkSize(t, a.Resize(11, 100), 11, 100)
}
-
func TestResize2(t *testing.T) {
var a Vector
checkSize(t, &a, 0, 0)
@@ -62,7 +59,6 @@ func TestResize2(t *testing.T) {
}
}
-
func checkZero(t *testing.T, a *Vector, i int) {
for j := 0; j < i; j++ {
if a.At(j) == zero {
@@ -82,7 +78,6 @@ func checkZero(t *testing.T, a *Vector, i int) {
}
}
-
func TestTrailingElements(t *testing.T) {
var a Vector
for i := 0; i < 10; i++ {
@@ -95,7 +90,6 @@ func TestTrailingElements(t *testing.T) {
checkZero(t, &a, 5)
}
-
func TestAccess(t *testing.T) {
const n = 100
var a Vector
@@ -120,7 +114,6 @@ func TestAccess(t *testing.T) {
}
}
-
func TestInsertDeleteClear(t *testing.T) {
const n = 100
var a Vector
@@ -207,7 +200,6 @@ func TestInsertDeleteClear(t *testing.T) {
}
}
-
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) {
@@ -223,7 +215,6 @@ func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
}
}
-
func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
n := a + b + c
if x.Len() != n {
@@ -237,7 +228,6 @@ func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
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++ {
@@ -246,7 +236,6 @@ func make_vector(elt, len int) *Vector {
return x
}
-
func TestInsertVector(t *testing.T) {
// 1
a := make_vector(0, 0)
@@ -270,7 +259,6 @@ func TestInsertVector(t *testing.T) {
verify_pattern(t, a, 8, 1000, 2)
}
-
func TestDo(t *testing.T) {
const n = 25
const salt = 17
@@ -325,7 +313,6 @@ func TestDo(t *testing.T) {
}
-
func TestVectorCopy(t *testing.T) {
// verify Copy() returns a copy, not simply a slice of the original vector
const Len = 10
diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go
index 3a9d0231845..73223531e17 100644
--- a/libgo/go/crypto/aes/cipher.go
+++ b/libgo/go/crypto/aes/cipher.go
@@ -45,14 +45,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
// BlockSize returns the AES block size, 16 bytes.
// It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
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).
+// instead, use an encryption mode like CBC (see crypto/cipher/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
diff --git a/libgo/go/crypto/blowfish/cipher.go b/libgo/go/crypto/blowfish/cipher.go
index f3c5175acfa..6c37dfe9405 100644
--- a/libgo/go/crypto/blowfish/cipher.go
+++ b/libgo/go/crypto/blowfish/cipher.go
@@ -42,14 +42,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
// BlockSize returns the Blowfish block size, 8 bytes.
// It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
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).
+// instead, use an encryption mode like CBC (see crypto/cipher/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])
diff --git a/libgo/go/crypto/cast5/cast5.go b/libgo/go/crypto/cast5/cast5.go
index cb62e3132e8..e9d4a24e26b 100644
--- a/libgo/go/crypto/cast5/cast5.go
+++ b/libgo/go/crypto/cast5/cast5.go
@@ -20,7 +20,7 @@ type Cipher struct {
func NewCipher(key []byte) (c *Cipher, err os.Error) {
if len(key) != KeySize {
- return nil, os.ErrorString("CAST5: keys must be 16 bytes")
+ return nil, os.NewError("CAST5: keys must be 16 bytes")
}
c = new(Cipher)
diff --git a/libgo/go/crypto/cipher/ocfb.go b/libgo/go/crypto/cipher/ocfb.go
index b2d87759115..031e74a9dca 100644
--- a/libgo/go/crypto/cipher/ocfb.go
+++ b/libgo/go/crypto/cipher/ocfb.go
@@ -80,9 +80,10 @@ type ocfbDecrypter struct {
// 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. Resync determines if the
-// "resynchronization step" from RFC 4880, 13.9 step 7 is performed. Different
-// parts of OpenPGP vary on this point.
+// incorrect key is detected then nil is returned. On successful exit,
+// blockSize+2 bytes of decrypted data are written into prefix. Resync
+// determines if the "resynchronization step" from RFC 4880, 13.9 step 7 is
+// performed. Different parts of OpenPGP vary on this point.
func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Stream {
blockSize := block.BlockSize()
if len(prefix) != blockSize+2 {
@@ -118,6 +119,7 @@ func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Strea
x.fre[1] = prefix[blockSize+1]
x.outUsed = 2
}
+ copy(prefix, prefixCopy)
return x
}
diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go
index f0af8bb427e..a5f96fe942c 100644
--- a/libgo/go/crypto/dsa/dsa.go
+++ b/libgo/go/crypto/dsa/dsa.go
@@ -79,7 +79,7 @@ func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes
L = 3072
N = 256
default:
- return os.ErrorString("crypto/dsa: invalid ParameterSizes")
+ return os.NewError("crypto/dsa: invalid ParameterSizes")
}
qBytes := make([]byte, N/8)
@@ -158,7 +158,7 @@ GeneratePrimes:
// PrivateKey must already be valid (see GenerateParameters).
func GenerateKey(priv *PrivateKey, rand io.Reader) os.Error {
if priv.P == nil || priv.Q == nil || priv.G == nil {
- return os.ErrorString("crypto/dsa: parameters not set up before generating key")
+ return os.NewError("crypto/dsa: parameters not set up before generating key")
}
x := new(big.Int)
diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go
index 335c9645dc6..41835f1a9c8 100644
--- a/libgo/go/crypto/elliptic/elliptic.go
+++ b/libgo/go/crypto/elliptic/elliptic.go
@@ -284,7 +284,7 @@ func (curve *Curve) Marshal(x, y *big.Int) []byte {
return ret
}
-// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
+// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On
// error, x = nil.
func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) {
byteLen := (curve.BitSize + 7) >> 3
diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go
index 02083a98666..b7e7f035fa5 100644
--- a/libgo/go/crypto/elliptic/elliptic_test.go
+++ b/libgo/go/crypto/elliptic/elliptic_test.go
@@ -321,8 +321,8 @@ func TestMarshal(t *testing.T) {
t.Error(err)
return
}
- serialised := p224.Marshal(x, y)
- xx, yy := p224.Unmarshal(serialised)
+ serialized := p224.Marshal(x, y)
+ xx, yy := p224.Unmarshal(serialized)
if xx == nil {
t.Error("failed to unmarshal")
return
diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go
index 40adbad0408..bcae63b8af8 100644
--- a/libgo/go/crypto/hmac/hmac_test.go
+++ b/libgo/go/crypto/hmac/hmac_test.go
@@ -190,7 +190,7 @@ func TestHMAC(t *testing.T) {
continue
}
- // Repetive Sum() calls should return the same value
+ // Repetitive Sum() calls should return the same value
for k := 0; k < 2; k++ {
sum := fmt.Sprintf("%x", h.Sum())
if sum != tt.out {
diff --git a/libgo/go/crypto/ocsp/ocsp.go b/libgo/go/crypto/ocsp/ocsp.go
index acd75b8b06e..7ea7a1e825c 100644
--- a/libgo/go/crypto/ocsp/ocsp.go
+++ b/libgo/go/crypto/ocsp/ocsp.go
@@ -13,6 +13,7 @@ import (
"crypto/rsa"
_ "crypto/sha1"
"crypto/x509"
+ "crypto/x509/pkix"
"os"
"time"
)
@@ -32,21 +33,8 @@ const (
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
+ HashAlgorithm pkix.AlgorithmIdentifier
NameHash []byte
IssuerKeyHash []byte
SerialNumber asn1.RawValue
@@ -54,7 +42,7 @@ type certID struct {
type responseASN1 struct {
Status asn1.Enumerated
- Response responseBytes "explicit,tag:0"
+ Response responseBytes `asn1:"explicit,tag:0"`
}
type responseBytes struct {
@@ -64,32 +52,32 @@ type responseBytes struct {
type basicResponse struct {
TBSResponseData responseData
- SignatureAlgorithm algorithmIdentifier
+ SignatureAlgorithm pkix.AlgorithmIdentifier
Signature asn1.BitString
- Certificates []asn1.RawValue "explicit,tag:0,optional"
+ Certificates []asn1.RawValue `asn1:"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"
+ Version int `asn1:"optional,default:1,explicit,tag:0"`
+ RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
+ KeyHash []byte `asn1:"optional,explicit,tag:2"`
ProducedAt *time.Time
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"
+ Good asn1.Flag `asn1:"explicit,tag:0,optional"`
+ Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
+ Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
ThisUpdate *time.Time
- NextUpdate *time.Time "explicit,tag:0,optional"
+ NextUpdate *time.Time `asn1:"explicit,tag:0,optional"`
}
type revokedInfo struct {
RevocationTime *time.Time
- Reason int "explicit,tag:0,optional"
+ Reason int `asn1:"explicit,tag:0,optional"`
}
// This is the exposed reflection of the internal OCSP structures.
diff --git a/libgo/go/crypto/openpgp/armor/armor.go b/libgo/go/crypto/openpgp/armor/armor.go
index 8da612c5007..9c4180d6d6d 100644
--- a/libgo/go/crypto/openpgp/armor/armor.go
+++ b/libgo/go/crypto/openpgp/armor/armor.go
@@ -153,7 +153,7 @@ func (r *openpgpReader) Read(p []byte) (n int, err os.Error) {
// 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
+// given Reader is not usable after calling this function: an arbitrary amount
// of data may have been read past the end of the block.
func Decode(in io.Reader) (p *Block, err os.Error) {
r, _ := bufio.NewReaderSize(in, 100)
diff --git a/libgo/go/crypto/openpgp/canonical_text_test.go b/libgo/go/crypto/openpgp/canonical_text_test.go
index 69ecf91a835..ccf2910cc6c 100644
--- a/libgo/go/crypto/openpgp/canonical_text_test.go
+++ b/libgo/go/crypto/openpgp/canonical_text_test.go
@@ -30,7 +30,6 @@ func (r recordingHash) Size() int {
panic("shouldn't be called")
}
-
func testCanonicalText(t *testing.T, input, expected string) {
r := recordingHash{bytes.NewBuffer(nil)}
c := NewCanonicalTextHash(r)
diff --git a/libgo/go/crypto/openpgp/elgamal/elgamal.go b/libgo/go/crypto/openpgp/elgamal/elgamal.go
new file mode 100644
index 00000000000..99a6e3e1f2d
--- /dev/null
+++ b/libgo/go/crypto/openpgp/elgamal/elgamal.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package elgamal implements ElGamal encryption, suitable for OpenPGP,
+// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
+// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
+// n. 4, 1985, pp. 469-472.
+//
+// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
+// unsuitable for other protocols. RSA should be used in preference in any
+// case.
+package elgamal
+
+import (
+ "big"
+ "crypto/rand"
+ "crypto/subtle"
+ "io"
+ "os"
+)
+
+// PublicKey represents an ElGamal public key.
+type PublicKey struct {
+ G, P, Y *big.Int
+}
+
+// PrivateKey represents an ElGamal private key.
+type PrivateKey struct {
+ PublicKey
+ X *big.Int
+}
+
+// Encrypt encrypts the given message to the given public key. The result is a
+// pair of integers. Errors can result from reading random, or because msg is
+// too large to be encrypted to the public key.
+func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err os.Error) {
+ pLen := (pub.P.BitLen() + 7) / 8
+ if len(msg) > pLen-11 {
+ err = os.NewError("elgamal: message too long")
+ return
+ }
+
+ // EM = 0x02 || PS || 0x00 || M
+ em := make([]byte, pLen-1)
+ em[0] = 2
+ ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err = nonZeroRandomBytes(ps, random)
+ if err != nil {
+ return
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ m := new(big.Int).SetBytes(em)
+
+ k, err := rand.Int(random, pub.P)
+ if err != nil {
+ return
+ }
+
+ c1 = new(big.Int).Exp(pub.G, k, pub.P)
+ s := new(big.Int).Exp(pub.Y, k, pub.P)
+ c2 = s.Mul(s, m)
+ c2.Mod(c2, pub.P)
+
+ return
+}
+
+// Decrypt takes two integers, resulting from an ElGamal encryption, and
+// returns the plaintext of the message. An error can result only if the
+// ciphertext is invalid. Users should keep in mind that this is a padding
+// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
+// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
+// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
+// Bleichenbacher, Advances in Cryptology (Crypto '98),
+func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err os.Error) {
+ s := new(big.Int).Exp(c1, priv.X, priv.P)
+ s.ModInverse(s, priv.P)
+ s.Mul(s, c2)
+ s.Mod(s, priv.P)
+ em := s.Bytes()
+
+ firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
+
+ // The remainder of the plaintext must be a string of non-zero random
+ // octets, followed by a 0, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the zero.
+ // index: the offset of the first zero byte.
+ var lookingForIndex, index int
+ lookingForIndex = 1
+
+ for i := 1; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
+ return nil, os.NewError("elgamal: decryption error")
+ }
+ return em[index+1:], nil
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
+ _, err = io.ReadFull(rand, s)
+ if err != nil {
+ return
+ }
+
+ for i := 0; i < len(s); i++ {
+ for s[i] == 0 {
+ _, err = io.ReadFull(rand, s[i:i+1])
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
diff --git a/libgo/go/crypto/openpgp/elgamal/elgamal_test.go b/libgo/go/crypto/openpgp/elgamal/elgamal_test.go
new file mode 100644
index 00000000000..101121aa658
--- /dev/null
+++ b/libgo/go/crypto/openpgp/elgamal/elgamal_test.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elgamal
+
+import (
+ "big"
+ "bytes"
+ "crypto/rand"
+ "testing"
+)
+
+// This is the 1024-bit MODP group from RFC 5114, section 2.1:
+const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
+
+const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
+
+func fromHex(hex string) *big.Int {
+ n, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("failed to parse hex number")
+ }
+ return n
+}
+
+func TestEncryptDecrypt(t *testing.T) {
+ priv := &PrivateKey{
+ PublicKey: PublicKey{
+ G: fromHex(generatorHex),
+ P: fromHex(primeHex),
+ },
+ X: fromHex("42"),
+ }
+ priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
+
+ message := []byte("hello world")
+ c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
+ if err != nil {
+ t.Errorf("error encrypting: %s", err)
+ }
+ message2, err := Decrypt(priv, c1, c2)
+ if err != nil {
+ t.Errorf("error decrypting: %s", err)
+ }
+ if !bytes.Equal(message2, message) {
+ t.Errorf("decryption failed, got: %x, want: %x", message2, message)
+ }
+}
diff --git a/libgo/go/crypto/openpgp/keys.go b/libgo/go/crypto/openpgp/keys.go
index 6c03f882831..c70fb792704 100644
--- a/libgo/go/crypto/openpgp/keys.go
+++ b/libgo/go/crypto/openpgp/keys.go
@@ -5,11 +5,14 @@
package openpgp
import (
+ "crypto"
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
+ "crypto/rsa"
"io"
"os"
+ "time"
)
// PublicKeyType is the armor type for a PGP public key.
@@ -62,6 +65,78 @@ type KeyRing interface {
DecryptionKeys() []Key
}
+// primaryIdentity returns the Identity marked as primary or the first identity
+// if none are so marked.
+func (e *Entity) primaryIdentity() *Identity {
+ var firstIdentity *Identity
+ for _, ident := range e.Identities {
+ if firstIdentity == nil {
+ firstIdentity = ident
+ }
+ if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
+ return ident
+ }
+ }
+ return firstIdentity
+}
+
+// encryptionKey returns the best candidate Key for encrypting a message to the
+// given Entity.
+func (e *Entity) encryptionKey() Key {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications && subkey.PublicKey.PubKeyAlgo.CanEncrypt() {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ i := e.primaryIdentity()
+
+ if e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
+ // If we don't have any candidate subkeys for encryption and
+ // the primary key doesn't have any usage metadata then we
+ // assume that the primary key is ok. Or, if the primary key is
+ // marked as ok to encrypt to, then we can obviously use it.
+ if candidateSubkey == -1 && !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && i.SelfSignature.FlagsValid {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
+ }
+ }
+
+ if candidateSubkey != -1 {
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
+ }
+
+ // This Entity appears to be signing only.
+ return Key{}
+}
+
+// signingKey return the best candidate Key for signing a message with this
+// Entity.
+func (e *Entity) signingKey() Key {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid && subkey.Sig.FlagSign && subkey.PublicKey.PubKeyAlgo.CanSign() {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ i := e.primaryIdentity()
+
+ // If we have no candidate subkey then we assume that it's ok to sign
+ // with the primary key.
+ if candidateSubkey == -1 || i.SelfSignature.FlagsValid && i.SelfSignature.FlagSign {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
+ }
+
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
+}
+
// An EntityList contains one or more Entities.
type EntityList []*Entity
@@ -197,6 +272,10 @@ func readEntity(packets *packet.Reader) (*Entity, os.Error) {
}
}
+ if !e.PrimaryKey.PubKeyAlgo.CanSign() {
+ return nil, error.StructuralError("primary key cannot be used for signatures")
+ }
+
var current *Identity
EachPacket:
for {
@@ -227,7 +306,7 @@ EachPacket:
return nil, error.StructuralError("user ID packet not followed by self-signature")
}
- if sig.SigType == packet.SigTypePositiveCert && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
+ if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, sig); err != nil {
return nil, error.StructuralError("user ID self-signature invalid: " + err.String())
}
@@ -297,3 +376,170 @@ func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *p
e.Subkeys = append(e.Subkeys, subKey)
return nil
}
+
+const defaultRSAKeyBits = 2048
+
+// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
+// single identity composed of the given full name, comment and email, any of
+// which may be empty but must not contain any of "()<>\x00".
+func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email string) (*Entity, os.Error) {
+ uid := packet.NewUserId(name, comment, email)
+ if uid == nil {
+ return nil, error.InvalidArgumentError("user id field contained invalid characters")
+ }
+ signingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits)
+ if err != nil {
+ return nil, err
+ }
+ encryptingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits)
+ if err != nil {
+ return nil, err
+ }
+
+ t := uint32(currentTimeSecs)
+
+ e := &Entity{
+ PrimaryKey: packet.NewRSAPublicKey(t, &signingPriv.PublicKey, false /* not a subkey */ ),
+ PrivateKey: packet.NewRSAPrivateKey(t, signingPriv, false /* not a subkey */ ),
+ Identities: make(map[string]*Identity),
+ }
+ isPrimaryId := true
+ e.Identities[uid.Id] = &Identity{
+ Name: uid.Name,
+ UserId: uid,
+ SelfSignature: &packet.Signature{
+ CreationTime: t,
+ SigType: packet.SigTypePositiveCert,
+ PubKeyAlgo: packet.PubKeyAlgoRSA,
+ Hash: crypto.SHA256,
+ IsPrimaryId: &isPrimaryId,
+ FlagsValid: true,
+ FlagSign: true,
+ FlagCertify: true,
+ IssuerKeyId: &e.PrimaryKey.KeyId,
+ },
+ }
+
+ e.Subkeys = make([]Subkey, 1)
+ e.Subkeys[0] = Subkey{
+ PublicKey: packet.NewRSAPublicKey(t, &encryptingPriv.PublicKey, true /* is a subkey */ ),
+ PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true /* is a subkey */ ),
+ Sig: &packet.Signature{
+ CreationTime: t,
+ SigType: packet.SigTypeSubkeyBinding,
+ PubKeyAlgo: packet.PubKeyAlgoRSA,
+ Hash: crypto.SHA256,
+ FlagsValid: true,
+ FlagEncryptStorage: true,
+ FlagEncryptCommunications: true,
+ IssuerKeyId: &e.PrimaryKey.KeyId,
+ },
+ }
+
+ return e, nil
+}
+
+// SerializePrivate serializes an Entity, including private key material, to
+// the given Writer. For now, it must only be used on an Entity returned from
+// NewEntity.
+func (e *Entity) SerializePrivate(w io.Writer) (err os.Error) {
+ err = e.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return
+ }
+ err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey)
+ if err != nil {
+ return
+ }
+ err = ident.SelfSignature.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey)
+ if err != nil {
+ return
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ return nil
+}
+
+// Serialize writes the public part of the given Entity to w. (No private
+// key material will be output).
+func (e *Entity) Serialize(w io.Writer) os.Error {
+ err := e.PrimaryKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return err
+ }
+ err = ident.SelfSignature.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, sig := range ident.Signatures {
+ err = sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PublicKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SignIdentity adds a signature to e, from signer, attesting that identity is
+// associated with e. The provided identity must already be an element of
+// e.Identities and the private key of signer must have been decrypted if
+// necessary.
+func (e *Entity) SignIdentity(identity string, signer *Entity) os.Error {
+ if signer.PrivateKey == nil {
+ return error.InvalidArgumentError("signing Entity must have a private key")
+ }
+ if signer.PrivateKey.Encrypted {
+ return error.InvalidArgumentError("signing Entity's private key must be decrypted")
+ }
+ ident, ok := e.Identities[identity]
+ if !ok {
+ return error.InvalidArgumentError("given identity string not found in Entity")
+ }
+
+ sig := &packet.Signature{
+ SigType: packet.SigTypeGenericCert,
+ PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
+ Hash: crypto.SHA256,
+ CreationTime: uint32(time.Seconds()),
+ IssuerKeyId: &signer.PrivateKey.KeyId,
+ }
+ if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil {
+ return err
+ }
+ ident.Signatures = append(ident.Signatures, sig)
+ return nil
+}
diff --git a/libgo/go/crypto/openpgp/packet/encrypted_key.go b/libgo/go/crypto/openpgp/packet/encrypted_key.go
index b11a9b8301a..b4730cbc9bc 100644
--- a/libgo/go/crypto/openpgp/packet/encrypted_key.go
+++ b/libgo/go/crypto/openpgp/packet/encrypted_key.go
@@ -5,6 +5,8 @@
package packet
import (
+ "big"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/rand"
"crypto/rsa"
@@ -14,14 +16,17 @@ import (
"strconv"
)
+const encryptedKeyVersion = 3
+
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
// section 5.1.
type EncryptedKey struct {
KeyId uint64
Algo PublicKeyAlgorithm
- Encrypted []byte
CipherFunc CipherFunction // only valid after a successful Decrypt
Key []byte // only valid after a successful Decrypt
+
+ encryptedMPI1, encryptedMPI2 []byte
}
func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
@@ -30,37 +35,134 @@ func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
if err != nil {
return
}
- if buf[0] != 3 {
+ if buf[0] != encryptedKeyVersion {
return error.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
}
e.KeyId = binary.BigEndian.Uint64(buf[1:9])
e.Algo = PublicKeyAlgorithm(buf[9])
- if e.Algo == PubKeyAlgoRSA || e.Algo == PubKeyAlgoRSAEncryptOnly {
- e.Encrypted, _, err = readMPI(r)
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ e.encryptedMPI1, _, err = readMPI(r)
+ case PubKeyAlgoElGamal:
+ e.encryptedMPI1, _, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ e.encryptedMPI2, _, err = readMPI(r)
}
_, err = consumeAll(r)
return
}
-// DecryptRSA decrypts an RSA encrypted session key with the given private key.
-func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) {
- if e.Algo != PubKeyAlgoRSA && e.Algo != PubKeyAlgoRSAEncryptOnly {
- return error.InvalidArgumentError("EncryptedKey not RSA encrypted")
+func checksumKeyMaterial(key []byte) uint16 {
+ var checksum uint16
+ for _, v := range key {
+ checksum += uint16(v)
}
- b, err := rsa.DecryptPKCS1v15(rand.Reader, priv, e.Encrypted)
+ return checksum
+}
+
+// Decrypt decrypts an encrypted session key with the given private key. The
+// private key must have been decrypted first.
+func (e *EncryptedKey) Decrypt(priv *PrivateKey) os.Error {
+ var err os.Error
+ var b []byte
+
+ // TODO(agl): use session key decryption routines here to avoid
+ // padding oracle attacks.
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ b, err = rsa.DecryptPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1)
+ case PubKeyAlgoElGamal:
+ c1 := new(big.Int).SetBytes(e.encryptedMPI1)
+ c2 := new(big.Int).SetBytes(e.encryptedMPI2)
+ b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
+ default:
+ err = error.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
+ }
+
if err != nil {
- return
+ return err
}
+
e.CipherFunc = CipherFunction(b[0])
e.Key = b[1 : len(b)-2]
expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
- var checksum uint16
- for _, v := range e.Key {
- checksum += uint16(v)
- }
+ checksum := checksumKeyMaterial(e.Key)
if checksum != expectedChecksum {
return error.StructuralError("EncryptedKey checksum incorrect")
}
- return
+ return nil
+}
+
+// SerializeEncryptedKey serializes an encrypted key packet to w that contains
+// key, encrypted to pub.
+func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) os.Error {
+ var buf [10]byte
+ buf[0] = encryptedKeyVersion
+ binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
+ buf[9] = byte(pub.PubKeyAlgo)
+
+ keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */ )
+ keyBlock[0] = byte(cipherFunc)
+ copy(keyBlock[1:], key)
+ checksum := checksumKeyMaterial(key)
+ keyBlock[1+len(key)] = byte(checksum >> 8)
+ keyBlock[1+len(key)+1] = byte(checksum)
+
+ switch pub.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ return serializeEncryptedKeyRSA(w, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
+ case PubKeyAlgoElGamal:
+ return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
+ case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
+ return error.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+ }
+
+ return error.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+}
+
+func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) os.Error {
+ cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
+ if err != nil {
+ return error.InvalidArgumentError("RSA encryption failed: " + err.String())
+ }
+
+ packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
+}
+
+func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) os.Error {
+ c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
+ if err != nil {
+ return error.InvalidArgumentError("ElGamal encryption failed: " + err.String())
+ }
+
+ packetLen := 10 /* header length */
+ packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
+ packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, c1)
+ if err != nil {
+ return err
+ }
+ return writeBig(w, c2)
}
diff --git a/libgo/go/crypto/openpgp/packet/encrypted_key_test.go b/libgo/go/crypto/openpgp/packet/encrypted_key_test.go
index 755ae7a3074..b402245bdae 100644
--- a/libgo/go/crypto/openpgp/packet/encrypted_key_test.go
+++ b/libgo/go/crypto/openpgp/packet/encrypted_key_test.go
@@ -6,6 +6,8 @@ package packet
import (
"big"
+ "bytes"
+ "crypto/rand"
"crypto/rsa"
"fmt"
"testing"
@@ -19,7 +21,27 @@ func bigFromBase10(s string) *big.Int {
return b
}
-func TestEncryptedKey(t *testing.T) {
+var encryptedKeyPub = rsa.PublicKey{
+ E: 65537,
+ N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+}
+
+var encryptedKeyRSAPriv = &rsa.PrivateKey{
+ PublicKey: encryptedKeyPub,
+ D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+}
+
+var encryptedKeyPriv = &PrivateKey{
+ PublicKey: PublicKey{
+ PubKeyAlgo: PubKeyAlgoRSA,
+ },
+ PrivateKey: encryptedKeyRSAPriv,
+}
+
+func TestDecryptingEncryptedKey(t *testing.T) {
+ const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
+ const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
+
p, err := Read(readerFromHex(encryptedKeyHex))
if err != nil {
t.Errorf("error from Read: %s", err)
@@ -36,23 +58,63 @@ func TestEncryptedKey(t *testing.T) {
return
}
- pub := rsa.PublicKey{
- E: 65537,
- N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+ err = ek.Decrypt(encryptedKeyPriv)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ if ek.CipherFunc != CipherAES256 {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ keyHex := fmt.Sprintf("%x", ek.Key)
+ if keyHex != expectedKeyHex {
+ t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
+ }
+}
+
+func TestEncryptingEncryptedKey(t *testing.T) {
+ key := []byte{1, 2, 3, 4}
+ const expectedKeyHex = "01020304"
+ const keyId = 42
+
+ pub := &PublicKey{
+ PublicKey: &encryptedKeyPub,
+ KeyId: keyId,
+ PubKeyAlgo: PubKeyAlgoRSAEncryptOnly,
+ }
+
+ buf := new(bytes.Buffer)
+ err := SerializeEncryptedKey(buf, rand.Reader, pub, CipherAES128, key)
+ if err != nil {
+ t.Errorf("error writing encrypted key packet: %s", err)
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+ ek, ok := p.(*EncryptedKey)
+ if !ok {
+ t.Errorf("didn't parse an EncryptedKey, got %#v", p)
+ return
}
- priv := &rsa.PrivateKey{
- PublicKey: pub,
- D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+ if ek.KeyId != keyId || ek.Algo != PubKeyAlgoRSAEncryptOnly {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
}
- err = ek.DecryptRSA(priv)
+ err = ek.Decrypt(encryptedKeyPriv)
if err != nil {
- t.Errorf("error from DecryptRSA: %s", err)
+ t.Errorf("error from Decrypt: %s", err)
return
}
- if ek.CipherFunc != CipherAES256 {
+ if ek.CipherFunc != CipherAES128 {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
@@ -62,6 +124,3 @@ func TestEncryptedKey(t *testing.T) {
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
}
}
-
-const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
-const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
diff --git a/libgo/go/crypto/openpgp/packet/literal.go b/libgo/go/crypto/openpgp/packet/literal.go
index 04f50e53e13..9411572d7c9 100644
--- a/libgo/go/crypto/openpgp/packet/literal.go
+++ b/libgo/go/crypto/openpgp/packet/literal.go
@@ -51,3 +51,40 @@ func (l *LiteralData) parse(r io.Reader) (err os.Error) {
l.Body = r
return
}
+
+// SerializeLiteral serializes a literal data packet to w and returns a
+// WriteCloser to which the data itself can be written and which MUST be closed
+// on completion. The fileName is truncated to 255 bytes.
+func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err os.Error) {
+ var buf [4]byte
+ buf[0] = 't'
+ if isBinary {
+ buf[0] = 'b'
+ }
+ if len(fileName) > 255 {
+ fileName = fileName[:255]
+ }
+ buf[1] = byte(len(fileName))
+
+ inner, err := serializeStreamHeader(w, packetTypeLiteralData)
+ if err != nil {
+ return
+ }
+
+ _, err = inner.Write(buf[:2])
+ if err != nil {
+ return
+ }
+ _, err = inner.Write([]byte(fileName))
+ if err != nil {
+ return
+ }
+ binary.BigEndian.PutUint32(buf[:], time)
+ _, err = inner.Write(buf[:])
+ if err != nil {
+ return
+ }
+
+ plaintext = inner
+ return
+}
diff --git a/libgo/go/crypto/openpgp/packet/one_pass_signature.go b/libgo/go/crypto/openpgp/packet/one_pass_signature.go
index acbf58bbefb..ca826e4f4d2 100644
--- a/libgo/go/crypto/openpgp/packet/one_pass_signature.go
+++ b/libgo/go/crypto/openpgp/packet/one_pass_signature.go
@@ -24,6 +24,8 @@ type OnePassSignature struct {
IsLast bool
}
+const onePassSignatureVersion = 3
+
func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
var buf [13]byte
@@ -31,7 +33,7 @@ func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
if err != nil {
return
}
- if buf[0] != 3 {
+ if buf[0] != onePassSignatureVersion {
err = error.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
}
@@ -47,3 +49,26 @@ func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
ops.IsLast = buf[12] != 0
return
}
+
+// Serialize marshals the given OnePassSignature to w.
+func (ops *OnePassSignature) Serialize(w io.Writer) os.Error {
+ var buf [13]byte
+ buf[0] = onePassSignatureVersion
+ buf[1] = uint8(ops.SigType)
+ var ok bool
+ buf[2], ok = s2k.HashToHashId(ops.Hash)
+ if !ok {
+ return error.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
+ }
+ buf[3] = uint8(ops.PubKeyAlgo)
+ binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
+ if ops.IsLast {
+ buf[12] = 1
+ }
+
+ if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
+ return err
+ }
+ _, err := w.Write(buf[:])
+ return err
+}
diff --git a/libgo/go/crypto/openpgp/packet/packet.go b/libgo/go/crypto/openpgp/packet/packet.go
index c0ec44dd8ec..1d7297e3884 100644
--- a/libgo/go/crypto/openpgp/packet/packet.go
+++ b/libgo/go/crypto/openpgp/packet/packet.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package packet implements parsing and serialisation of OpenPGP packets, as
+// Package packet implements parsing and serialization of OpenPGP packets, as
// specified in RFC 4880.
package packet
@@ -92,6 +92,46 @@ func (r *partialLengthReader) Read(p []byte) (n int, err os.Error) {
return
}
+// partialLengthWriter writes a stream of data using OpenPGP partial lengths.
+// See RFC 4880, section 4.2.2.4.
+type partialLengthWriter struct {
+ w io.WriteCloser
+ lengthByte [1]byte
+}
+
+func (w *partialLengthWriter) Write(p []byte) (n int, err os.Error) {
+ for len(p) > 0 {
+ for power := uint(14); power < 32; power-- {
+ l := 1 << power
+ if len(p) >= l {
+ w.lengthByte[0] = 224 + uint8(power)
+ _, err = w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return
+ }
+ var m int
+ m, err = w.w.Write(p[:l])
+ n += m
+ if err != nil {
+ return
+ }
+ p = p[l:]
+ break
+ }
+ }
+ }
+ return
+}
+
+func (w *partialLengthWriter) Close() os.Error {
+ w.lengthByte[0] = 0
+ _, err := w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return err
+ }
+ return w.w.Close()
+}
+
// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
// underlying Reader returns EOF before the limit has been reached.
type spanReader struct {
@@ -195,6 +235,20 @@ func serializeHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
return
}
+// serializeStreamHeader writes an OpenPGP packet header to w where the
+// length of the packet is unknown. It returns a io.WriteCloser which can be
+// used to write the contents of the packet. See RFC 4880, section 4.2.
+func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err os.Error) {
+ var buf [1]byte
+ buf[0] = 0x80 | 0x40 | byte(ptype)
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ out = &partialLengthWriter{w: w}
+ return
+}
+
// Packet represents an OpenPGP packet. Users are expected to try casting
// instances of this interface to specific packet types.
type Packet interface {
@@ -301,12 +355,12 @@ type SignatureType uint8
const (
SigTypeBinary SignatureType = 0
- SigTypeText = 1
- SigTypeGenericCert = 0x10
- SigTypePersonaCert = 0x11
- SigTypeCasualCert = 0x12
- SigTypePositiveCert = 0x13
- SigTypeSubkeyBinding = 0x18
+ SigTypeText = 1
+ SigTypeGenericCert = 0x10
+ SigTypePersonaCert = 0x11
+ SigTypeCasualCert = 0x12
+ SigTypePositiveCert = 0x13
+ SigTypeSubkeyBinding = 0x18
)
// PublicKeyAlgorithm represents the different public key system specified for
@@ -318,23 +372,43 @@ const (
PubKeyAlgoRSA PublicKeyAlgorithm = 1
PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
- PubKeyAlgoElgamal PublicKeyAlgorithm = 16
+ PubKeyAlgoElGamal PublicKeyAlgorithm = 16
PubKeyAlgoDSA PublicKeyAlgorithm = 17
)
+// CanEncrypt returns true if it's possible to encrypt a message to a public
+// key of the given type.
+func (pka PublicKeyAlgorithm) CanEncrypt() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal:
+ return true
+ }
+ return false
+}
+
+// CanSign returns true if it's possible for a public key of the given type to
+// sign a message.
+func (pka PublicKeyAlgorithm) CanSign() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
+ return true
+ }
+ return false
+}
+
// CipherFunction represents the different block ciphers specified for OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
type CipherFunction uint8
const (
- CipherCAST5 = 3
- CipherAES128 = 7
- CipherAES192 = 8
- CipherAES256 = 9
+ CipherCAST5 CipherFunction = 3
+ CipherAES128 CipherFunction = 7
+ CipherAES192 CipherFunction = 8
+ CipherAES256 CipherFunction = 9
)
-// keySize returns the key size, in bytes, of cipher.
-func (cipher CipherFunction) keySize() int {
+// KeySize returns the key size, in bytes, of cipher.
+func (cipher CipherFunction) KeySize() int {
switch cipher {
case CipherCAST5:
return cast5.KeySize
@@ -386,6 +460,14 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) {
return
}
+// mpiLength returns the length of the given *big.Int when serialized as an
+// MPI.
+func mpiLength(n *big.Int) (mpiLengthInBytes int) {
+ mpiLengthInBytes = 2 /* MPI length */
+ mpiLengthInBytes += (n.BitLen() + 7) / 8
+ return
+}
+
// writeMPI serializes a big integer to w.
func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err os.Error) {
_, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
diff --git a/libgo/go/crypto/openpgp/packet/packet_test.go b/libgo/go/crypto/openpgp/packet/packet_test.go
index 1a4692cd4f5..23d9978ae1f 100644
--- a/libgo/go/crypto/openpgp/packet/packet_test.go
+++ b/libgo/go/crypto/openpgp/packet/packet_test.go
@@ -210,3 +210,47 @@ func TestSerializeHeader(t *testing.T) {
}
}
}
+
+func TestPartialLengths(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ w := new(partialLengthWriter)
+ w.w = noOpCloser{buf}
+
+ const maxChunkSize = 64
+
+ var b [maxChunkSize]byte
+ var n uint8
+ for l := 1; l <= maxChunkSize; l++ {
+ for i := 0; i < l; i++ {
+ b[i] = n
+ n++
+ }
+ m, err := w.Write(b[:l])
+ if m != l {
+ t.Errorf("short write got: %d want: %d", m, l)
+ }
+ if err != nil {
+ t.Errorf("error from write: %s", err)
+ }
+ }
+ w.Close()
+
+ want := (maxChunkSize * (maxChunkSize + 1)) / 2
+ copyBuf := bytes.NewBuffer(nil)
+ r := &partialLengthReader{buf, 0, true}
+ m, err := io.Copy(copyBuf, r)
+ if m != int64(want) {
+ t.Errorf("short copy got: %d want: %d", m, want)
+ }
+ if err != nil {
+ t.Errorf("error from copy: %s", err)
+ }
+
+ copyBytes := copyBuf.Bytes()
+ for i := 0; i < want; i++ {
+ if copyBytes[i] != uint8(i) {
+ t.Errorf("bad pattern in copy at %d", i)
+ break
+ }
+ }
+}
diff --git a/libgo/go/crypto/openpgp/packet/private_key.go b/libgo/go/crypto/openpgp/packet/private_key.go
index fde2a9933d8..6f8133d981a 100644
--- a/libgo/go/crypto/openpgp/packet/private_key.go
+++ b/libgo/go/crypto/openpgp/packet/private_key.go
@@ -9,6 +9,7 @@ import (
"bytes"
"crypto/cipher"
"crypto/dsa"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/openpgp/s2k"
"crypto/rsa"
@@ -32,6 +33,13 @@ type PrivateKey struct {
iv []byte
}
+func NewRSAPrivateKey(currentTimeSecs uint32, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewRSAPublicKey(currentTimeSecs, &priv.PublicKey, isSubkey)
+ pk.PrivateKey = priv
+ return pk
+}
+
func (pk *PrivateKey) parse(r io.Reader) (err os.Error) {
err = (&pk.PublicKey).parse(r)
if err != nil {
@@ -91,13 +99,90 @@ func (pk *PrivateKey) parse(r io.Reader) (err os.Error) {
return
}
+func mod64kHash(d []byte) uint16 {
+ h := uint16(0)
+ for i := 0; i < len(d); i += 2 {
+ v := uint16(d[i]) << 8
+ if i+1 < len(d) {
+ v += uint16(d[i+1])
+ }
+ h += v
+ }
+ return h
+}
+
+func (pk *PrivateKey) Serialize(w io.Writer) (err os.Error) {
+ // TODO(agl): support encrypted private keys
+ buf := bytes.NewBuffer(nil)
+ err = pk.PublicKey.serializeWithoutHeaders(buf)
+ if err != nil {
+ return
+ }
+ buf.WriteByte(0 /* no encryption */ )
+
+ privateKeyBuf := bytes.NewBuffer(nil)
+
+ switch priv := pk.PrivateKey.(type) {
+ case *rsa.PrivateKey:
+ err = serializeRSAPrivateKey(privateKeyBuf, priv)
+ default:
+ err = error.InvalidArgumentError("non-RSA private key")
+ }
+ if err != nil {
+ return
+ }
+
+ ptype := packetTypePrivateKey
+ contents := buf.Bytes()
+ privateKeyBytes := privateKeyBuf.Bytes()
+ if pk.IsSubkey {
+ ptype = packetTypePrivateSubkey
+ }
+ err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(privateKeyBytes)
+ if err != nil {
+ return
+ }
+
+ checksum := mod64kHash(privateKeyBytes)
+ var checksumBytes [2]byte
+ checksumBytes[0] = byte(checksum >> 8)
+ checksumBytes[1] = byte(checksum)
+ _, err = w.Write(checksumBytes[:])
+
+ return
+}
+
+func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) os.Error {
+ err := writeBig(w, priv.D)
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, priv.Primes[1])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, priv.Primes[0])
+ if err != nil {
+ return err
+ }
+ return writeBig(w, priv.Precomputed.Qinv)
+}
+
// Decrypt decrypts an encrypted private key using a passphrase.
func (pk *PrivateKey) Decrypt(passphrase []byte) os.Error {
if !pk.Encrypted {
return nil
}
- key := make([]byte, pk.cipher.keySize())
+ key := make([]byte, pk.cipher.KeySize())
pk.s2k(key, passphrase)
block := pk.cipher.new(key)
cfb := cipher.NewCFBDecrypter(block, pk.iv)
@@ -140,6 +225,8 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
return pk.parseRSAPrivateKey(data)
case PubKeyAlgoDSA:
return pk.parseDSAPrivateKey(data)
+ case PubKeyAlgoElGamal:
+ return pk.parseElGamalPrivateKey(data)
}
panic("impossible")
}
@@ -193,3 +280,22 @@ func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err os.Error) {
return nil
}
+
+func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err os.Error) {
+ pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
+ priv := new(elgamal.PrivateKey)
+ priv.PublicKey = *pub
+
+ buf := bytes.NewBuffer(data)
+ x, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ priv.X = new(big.Int).SetBytes(x)
+ pk.PrivateKey = priv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
diff --git a/libgo/go/crypto/openpgp/packet/private_key_test.go b/libgo/go/crypto/openpgp/packet/private_key_test.go
index e941cc735cf..60eebaa6b09 100644
--- a/libgo/go/crypto/openpgp/packet/private_key_test.go
+++ b/libgo/go/crypto/openpgp/packet/private_key_test.go
@@ -8,30 +8,50 @@ import (
"testing"
)
-func TestPrivateKeyRead(t *testing.T) {
- packet, err := Read(readerFromHex(privKeyHex))
- if err != nil {
- t.Error(err)
- return
- }
-
- privKey := packet.(*PrivateKey)
-
- if !privKey.Encrypted {
- t.Error("private key isn't encrypted")
- return
- }
-
- err = privKey.Decrypt([]byte("testing"))
- if err != nil {
- t.Error(err)
- return
- }
+var privateKeyTests = []struct {
+ privateKeyHex string
+ creationTime uint32
+}{
+ {
+ privKeyRSAHex,
+ 0x4cc349a8,
+ },
+ {
+ privKeyElGamalHex,
+ 0x4df9ee1a,
+ },
+}
- if privKey.CreationTime != 0x4cc349a8 || privKey.Encrypted {
- t.Errorf("failed to parse, got: %#v", privKey)
+func TestPrivateKeyRead(t *testing.T) {
+ for i, test := range privateKeyTests {
+ packet, err := Read(readerFromHex(test.privateKeyHex))
+ if err != nil {
+ t.Errorf("#%d: failed to parse: %s", i, err)
+ continue
+ }
+
+ privKey := packet.(*PrivateKey)
+
+ if !privKey.Encrypted {
+ t.Errorf("#%d: private key isn't encrypted", i)
+ continue
+ }
+
+ err = privKey.Decrypt([]byte("testing"))
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt: %s", i, err)
+ continue
+ }
+
+ if privKey.CreationTime != test.creationTime || privKey.Encrypted {
+ t.Errorf("#%d: bad result, got: %#v", i, privKey)
+ }
}
}
// Generated with `gpg --export-secret-keys "Test Key 2"`
-const privKeyHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+
+// Generated by `gpg --export-secret-keys` followed by a manual extraction of
+// the ElGamal subkey from the packets.
+const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"
diff --git a/libgo/go/crypto/openpgp/packet/public_key.go b/libgo/go/crypto/openpgp/packet/public_key.go
index cd4a9aebb60..e6b0ae5f3af 100644
--- a/libgo/go/crypto/openpgp/packet/public_key.go
+++ b/libgo/go/crypto/openpgp/packet/public_key.go
@@ -7,6 +7,7 @@ package packet
import (
"big"
"crypto/dsa"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/rsa"
"crypto/sha1"
@@ -30,6 +31,28 @@ type PublicKey struct {
n, e, p, q, g, y parsedMPI
}
+func fromBig(n *big.Int) parsedMPI {
+ return parsedMPI{
+ bytes: n.Bytes(),
+ bitLength: uint16(n.BitLen()),
+ }
+}
+
+// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
+func NewRSAPublicKey(creationTimeSecs uint32, pub *rsa.PublicKey, isSubkey bool) *PublicKey {
+ pk := &PublicKey{
+ CreationTime: creationTimeSecs,
+ PubKeyAlgo: PubKeyAlgoRSA,
+ PublicKey: pub,
+ IsSubkey: isSubkey,
+ n: fromBig(pub.N),
+ e: fromBig(big.NewInt(int64(pub.E))),
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return pk
+}
+
func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
// RFC 4880, section 5.5.2
var buf [6]byte
@@ -47,6 +70,8 @@ func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
err = pk.parseRSA(r)
case PubKeyAlgoDSA:
err = pk.parseDSA(r)
+ case PubKeyAlgoElGamal:
+ err = pk.parseElGamal(r)
default:
err = error.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
}
@@ -54,14 +79,17 @@ func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
return
}
+ pk.setFingerPrintAndKeyId()
+ return
+}
+
+func (pk *PublicKey) setFingerPrintAndKeyId() {
// RFC 4880, section 12.2
fingerPrint := sha1.New()
pk.SerializeSignaturePrefix(fingerPrint)
- pk.Serialize(fingerPrint)
+ pk.serializeWithoutHeaders(fingerPrint)
copy(pk.Fingerprint[:], fingerPrint.Sum())
pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
-
- return
}
// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
@@ -92,7 +120,7 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err os.Error) {
return
}
-// parseRSA parses DSA public key material from the given Reader. See RFC 4880,
+// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
@@ -121,6 +149,30 @@ func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
return
}
+// parseElGamal parses ElGamal public key material from the given Reader. See
+// RFC 4880, section 5.5.2.
+func (pk *PublicKey) parseElGamal(r io.Reader) (err os.Error) {
+ pk.p.bytes, pk.p.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.g.bytes, pk.g.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.y.bytes, pk.y.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ elgamal := new(elgamal.PublicKey)
+ elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
+ elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
+ elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
+ pk.PublicKey = elgamal
+ return
+}
+
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
// The prefix is used when calculating a signature over this public key. See
// RFC 4880, section 5.2.4.
@@ -135,6 +187,10 @@ func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
pLength += 2 + uint16(len(pk.q.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
+ case PubKeyAlgoElGamal:
+ pLength += 2 + uint16(len(pk.p.bytes))
+ pLength += 2 + uint16(len(pk.g.bytes))
+ pLength += 2 + uint16(len(pk.y.bytes))
default:
panic("unknown public key algorithm")
}
@@ -143,9 +199,40 @@ func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
return
}
-// Serialize marshals the PublicKey to w in the form of an OpenPGP public key
-// packet, not including the packet header.
func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
+ length := 6 // 6 byte header
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ length += 2 + len(pk.n.bytes)
+ length += 2 + len(pk.e.bytes)
+ case PubKeyAlgoDSA:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.q.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ case PubKeyAlgoElGamal:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ default:
+ panic("unknown public key algorithm")
+ }
+
+ packetType := packetTypePublicKey
+ if pk.IsSubkey {
+ packetType = packetTypePublicSubkey
+ }
+ err = serializeHeader(w, packetType, length)
+ if err != nil {
+ return
+ }
+ return pk.serializeWithoutHeaders(w)
+}
+
+// serializeWithoutHeaders marshals the PublicKey to w in the form of an
+// OpenPGP public key packet, not including the packet header.
+func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err os.Error) {
var buf [6]byte
buf[0] = 4
buf[1] = byte(pk.CreationTime >> 24)
@@ -164,13 +251,15 @@ func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
return writeMPIs(w, pk.n, pk.e)
case PubKeyAlgoDSA:
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
+ case PubKeyAlgoElGamal:
+ return writeMPIs(w, pk.p, pk.g, pk.y)
}
return error.InvalidArgumentError("bad public-key algorithm")
}
// CanSign returns true iff this public key can generate signatures
func (pk *PublicKey) CanSign() bool {
- return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElgamal
+ return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
}
// VerifySignature returns nil iff sig is a valid signature, made by this
@@ -194,14 +283,14 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E
switch pk.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
- err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature)
+ err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
if err != nil {
return error.SignatureError("RSA verification failure")
}
return nil
case PubKeyAlgoDSA:
dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
- if !dsa.Verify(dsaPublicKey, hashBytes, sig.DSASigR, sig.DSASigS) {
+ if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
return error.SignatureError("DSA verification failure")
}
return nil
@@ -211,34 +300,43 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E
panic("unreachable")
}
-// VerifyKeySignature returns nil iff sig is a valid signature, make by this
-// public key, of the public key in signed.
-func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err os.Error) {
- h := sig.Hash.New()
+// keySignatureHash returns a Hash of the message that needs to be signed for
+// pk to assert a subkey relationship to signed.
+func keySignatureHash(pk, signed *PublicKey, sig *Signature) (h hash.Hash, err os.Error) {
+ h = sig.Hash.New()
if h == nil {
- return error.UnsupportedError("hash function")
+ return nil, error.UnsupportedError("hash function")
}
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
- pk.Serialize(h)
+ pk.serializeWithoutHeaders(h)
signed.SerializeSignaturePrefix(h)
- signed.Serialize(h)
+ signed.serializeWithoutHeaders(h)
+ return
+}
+// VerifyKeySignature returns nil iff sig is a valid signature, made by this
+// public key, of signed.
+func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err os.Error) {
+ h, err := keySignatureHash(pk, signed, sig)
+ if err != nil {
+ return err
+ }
return pk.VerifySignature(h, sig)
}
-// VerifyUserIdSignature returns nil iff sig is a valid signature, make by this
-// public key, of the given user id.
-func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Error) {
- h := sig.Hash.New()
+// userIdSignatureHash returns a Hash of the message that needs to be signed
+// to assert that pk is a valid key for id.
+func userIdSignatureHash(id string, pk *PublicKey, sig *Signature) (h hash.Hash, err os.Error) {
+ h = sig.Hash.New()
if h == nil {
- return error.UnsupportedError("hash function")
+ return nil, error.UnsupportedError("hash function")
}
// RFC 4880, section 5.2.4
pk.SerializeSignaturePrefix(h)
- pk.Serialize(h)
+ pk.serializeWithoutHeaders(h)
var buf [5]byte
buf[0] = 0xb4
@@ -249,6 +347,16 @@ func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Er
h.Write(buf[:])
h.Write([]byte(id))
+ return
+}
+
+// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
+// public key, of id.
+func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Error) {
+ h, err := userIdSignatureHash(id, pk, sig)
+ if err != nil {
+ return err
+ }
return pk.VerifySignature(h, sig)
}
@@ -272,7 +380,7 @@ type parsedMPI struct {
bitLength uint16
}
-// writeMPIs is a utility function for serialising several big integers to the
+// writeMPIs is a utility function for serializing several big integers to the
// given Writer.
func writeMPIs(w io.Writer, mpis ...parsedMPI) (err os.Error) {
for _, mpi := range mpis {
diff --git a/libgo/go/crypto/openpgp/packet/public_key_test.go b/libgo/go/crypto/openpgp/packet/public_key_test.go
index 069388c14dc..6e8bfbce66e 100644
--- a/libgo/go/crypto/openpgp/packet/public_key_test.go
+++ b/libgo/go/crypto/openpgp/packet/public_key_test.go
@@ -28,12 +28,12 @@ func TestPublicKeyRead(t *testing.T) {
packet, err := Read(readerFromHex(test.hexData))
if err != nil {
t.Errorf("#%d: Read error: %s", i, err)
- return
+ continue
}
pk, ok := packet.(*PublicKey)
if !ok {
t.Errorf("#%d: failed to parse, got: %#v", i, packet)
- return
+ continue
}
if pk.PubKeyAlgo != test.pubKeyAlgo {
t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
@@ -57,6 +57,38 @@ func TestPublicKeyRead(t *testing.T) {
}
}
+func TestPublicKeySerialize(t *testing.T) {
+ for i, test := range pubKeyTests {
+ packet, err := Read(readerFromHex(test.hexData))
+ if err != nil {
+ t.Errorf("#%d: Read error: %s", i, err)
+ continue
+ }
+ pk, ok := packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse, got: %#v", i, packet)
+ continue
+ }
+ serializeBuf := bytes.NewBuffer(nil)
+ err = pk.Serialize(serializeBuf)
+ if err != nil {
+ t.Errorf("#%d: failed to serialize: %s", i, err)
+ continue
+ }
+
+ packet, err = Read(serializeBuf)
+ if err != nil {
+ t.Errorf("#%d: Read error (from serialized data): %s", i, err)
+ continue
+ }
+ pk, ok = packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse serialized data, got: %#v", i, packet)
+ continue
+ }
+ }
+}
+
const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb"
const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001"
diff --git a/libgo/go/crypto/openpgp/packet/signature.go b/libgo/go/crypto/openpgp/packet/signature.go
index 719657e76ee..7577e287588 100644
--- a/libgo/go/crypto/openpgp/packet/signature.go
+++ b/libgo/go/crypto/openpgp/packet/signature.go
@@ -5,7 +5,6 @@
package packet
import (
- "big"
"crypto"
"crypto/dsa"
"crypto/openpgp/error"
@@ -32,8 +31,11 @@ type Signature struct {
HashTag [2]byte
CreationTime uint32 // Unix epoch time
- RSASignature []byte
- DSASigR, DSASigS *big.Int
+ RSASignature parsedMPI
+ DSASigR, DSASigS parsedMPI
+
+ // rawSubpackets contains the unparsed subpackets, in order.
+ rawSubpackets []outputSubpacket
// The following are optional so are nil when not included in the
// signature.
@@ -128,14 +130,11 @@ func (sig *Signature) parse(r io.Reader) (err os.Error) {
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- sig.RSASignature, _, err = readMPI(r)
+ sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
case PubKeyAlgoDSA:
- var rBytes, sBytes []byte
- rBytes, _, err = readMPI(r)
- sig.DSASigR = new(big.Int).SetBytes(rBytes)
+ sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
if err == nil {
- sBytes, _, err = readMPI(r)
- sig.DSASigS = new(big.Int).SetBytes(sBytes)
+ sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
}
default:
panic("unreachable")
@@ -177,7 +176,11 @@ const (
// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err os.Error) {
// RFC 4880, section 5.2.3.1
- var length uint32
+ var (
+ length uint32
+ packetType signatureSubpacketType
+ isCritical bool
+ )
switch {
case subpacket[0] < 192:
length = uint32(subpacket[0])
@@ -207,10 +210,11 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
err = error.StructuralError("zero length signature subpacket")
return
}
- packetType := subpacket[0] & 0x7f
- isCritial := subpacket[0]&0x80 == 0x80
+ packetType = signatureSubpacketType(subpacket[0] & 0x7f)
+ isCritical = subpacket[0]&0x80 == 0x80
subpacket = subpacket[1:]
- switch signatureSubpacketType(packetType) {
+ sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
+ switch packetType {
case creationTimeSubpacket:
if !isHashed {
err = error.StructuralError("signature creation time in non-hashed area")
@@ -309,7 +313,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
}
default:
- if isCritial {
+ if isCritical {
err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
return
}
@@ -381,7 +385,6 @@ func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
func (sig *Signature) buildHashSuffix() (err os.Error) {
- sig.outSubpackets = sig.buildSubpackets()
hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
var ok bool
@@ -393,7 +396,7 @@ func (sig *Signature) buildHashSuffix() (err os.Error) {
sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
if !ok {
sig.HashSuffix = nil
- return error.InvalidArgumentError("hash cannot be repesented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
+ return error.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
}
sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
sig.HashSuffix[5] = byte(hashedSubpacketsLen)
@@ -420,45 +423,72 @@ func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err os.Error)
return
}
-// SignRSA signs a message with an RSA private key. The hash, h, must contain
+// Sign signs a message with a private key. The hash, h, must contain
// the hash of the message to be signed and will be mutated by this function.
// On success, the signature is stored in sig. Call Serialize to write it out.
-func (sig *Signature) SignRSA(h hash.Hash, priv *rsa.PrivateKey) (err os.Error) {
+func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey) (err os.Error) {
+ sig.outSubpackets = sig.buildSubpackets()
digest, err := sig.signPrepareHash(h)
if err != nil {
return
}
- sig.RSASignature, err = rsa.SignPKCS1v15(rand.Reader, priv, sig.Hash, digest)
+
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sig.RSASignature.bytes, err = rsa.SignPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
+ sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes))
+ case PubKeyAlgoDSA:
+ r, s, err := dsa.Sign(rand.Reader, priv.PrivateKey.(*dsa.PrivateKey), digest)
+ if err == nil {
+ sig.DSASigR.bytes = r.Bytes()
+ sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
+ sig.DSASigS.bytes = s.Bytes()
+ sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
+ }
+ default:
+ err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ }
+
return
}
-// SignDSA signs a message with a DSA private key. The hash, h, must contain
-// the hash of the message to be signed and will be mutated by this function.
-// On success, the signature is stored in sig. Call Serialize to write it out.
-func (sig *Signature) SignDSA(h hash.Hash, priv *dsa.PrivateKey) (err os.Error) {
- digest, err := sig.signPrepareHash(h)
+// SignUserId computes a signature from priv, asserting that pub is a valid
+// key for the identity id. On success, the signature is stored in sig. Call
+// Serialize to write it out.
+func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey) os.Error {
+ h, err := userIdSignatureHash(id, pub, sig)
if err != nil {
- return
+ return nil
}
- sig.DSASigR, sig.DSASigS, err = dsa.Sign(rand.Reader, priv, digest)
- return
+ return sig.Sign(h, priv)
+}
+
+// SignKey computes a signature from priv, asserting that pub is a subkey. On
+// success, the signature is stored in sig. Call Serialize to write it out.
+func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey) os.Error {
+ h, err := keySignatureHash(&priv.PublicKey, pub, sig)
+ if err != nil {
+ return err
+ }
+ return sig.Sign(h, priv)
}
// Serialize marshals sig to w. SignRSA or SignDSA must have been called first.
func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
- if sig.RSASignature == nil && sig.DSASigR == nil {
+ if len(sig.outSubpackets) == 0 {
+ sig.outSubpackets = sig.rawSubpackets
+ }
+ if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
return error.InvalidArgumentError("Signature: need to call SignRSA or SignDSA before Serialize")
}
sigLength := 0
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- sigLength = len(sig.RSASignature)
+ sigLength = 2 + len(sig.RSASignature.bytes)
case PubKeyAlgoDSA:
- sigLength = 2 /* MPI length */
- sigLength += (sig.DSASigR.BitLen() + 7) / 8
- sigLength += 2 /* MPI length */
- sigLength += (sig.DSASigS.BitLen() + 7) / 8
+ sigLength = 2 + len(sig.DSASigR.bytes)
+ sigLength += 2 + len(sig.DSASigS.bytes)
default:
panic("impossible")
}
@@ -466,7 +496,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
length := len(sig.HashSuffix) - 6 /* trailer not included */ +
2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
- 2 /* hash tag */ + 2 /* length of signature MPI */ + sigLength
+ 2 /* hash tag */ + sigLength
err = serializeHeader(w, packetTypeSignature, length)
if err != nil {
return
@@ -493,12 +523,9 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
switch sig.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
- err = writeMPI(w, 8*uint16(len(sig.RSASignature)), sig.RSASignature)
+ err = writeMPIs(w, sig.RSASignature)
case PubKeyAlgoDSA:
- err = writeBig(w, sig.DSASigR)
- if err == nil {
- err = writeBig(w, sig.DSASigS)
- }
+ err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
default:
panic("impossible")
}
@@ -509,6 +536,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
type outputSubpacket struct {
hashed bool // true if this subpacket is in the hashed area.
subpacketType signatureSubpacketType
+ isCritical bool
contents []byte
}
@@ -518,12 +546,12 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
creationTime[1] = byte(sig.CreationTime >> 16)
creationTime[2] = byte(sig.CreationTime >> 8)
creationTime[3] = byte(sig.CreationTime)
- subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, creationTime})
+ subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
if sig.IssuerKeyId != nil {
keyId := make([]byte, 8)
binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
- subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, keyId})
+ subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
}
return
diff --git a/libgo/go/crypto/openpgp/packet/signature_test.go b/libgo/go/crypto/openpgp/packet/signature_test.go
index 1305548b2ae..c1bbde8b0c3 100644
--- a/libgo/go/crypto/openpgp/packet/signature_test.go
+++ b/libgo/go/crypto/openpgp/packet/signature_test.go
@@ -12,9 +12,7 @@ import (
)
func TestSignatureRead(t *testing.T) {
- signatureData, _ := hex.DecodeString(signatureDataHex)
- buf := bytes.NewBuffer(signatureData)
- packet, err := Read(buf)
+ packet, err := Read(readerFromHex(signatureDataHex))
if err != nil {
t.Error(err)
return
@@ -25,4 +23,20 @@ func TestSignatureRead(t *testing.T) {
}
}
-const signatureDataHex = "89011c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
+func TestSignatureReserialize(t *testing.T) {
+ packet, _ := Read(readerFromHex(signatureDataHex))
+ sig := packet.(*Signature)
+ out := new(bytes.Buffer)
+ err := sig.Serialize(out)
+ if err != nil {
+ t.Errorf("error reserializing: %s", err)
+ return
+ }
+
+ expected, _ := hex.DecodeString(signatureDataHex)
+ if !bytes.Equal(expected, out.Bytes()) {
+ t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected))
+ }
+}
+
+const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
diff --git a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go
index d9010f88a3d..ad4f1d6212a 100644
--- a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go
+++ b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go
@@ -5,6 +5,7 @@
package packet
import (
+ "bytes"
"crypto/cipher"
"crypto/openpgp/error"
"crypto/openpgp/s2k"
@@ -27,6 +28,8 @@ type SymmetricKeyEncrypted struct {
encryptedKey []byte
}
+const symmetricKeyEncryptedVersion = 4
+
func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
// RFC 4880, section 5.3.
var buf [2]byte
@@ -34,12 +37,12 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
if err != nil {
return
}
- if buf[0] != 4 {
+ if buf[0] != symmetricKeyEncryptedVersion {
return error.UnsupportedError("SymmetricKeyEncrypted version")
}
ske.CipherFunc = CipherFunction(buf[1])
- if ske.CipherFunc.keySize() == 0 {
+ if ske.CipherFunc.KeySize() == 0 {
return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
}
@@ -75,7 +78,7 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
return nil
}
- key := make([]byte, ske.CipherFunc.keySize())
+ key := make([]byte, ske.CipherFunc.KeySize())
ske.s2k(key, passphrase)
if len(ske.encryptedKey) == 0 {
@@ -100,3 +103,60 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
ske.Encrypted = false
return nil
}
+
+// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
+// packet contains a random session key, encrypted by a key derived from the
+// given passphrase. The session key is returned and must be passed to
+// SerializeSymmetricallyEncrypted.
+func SerializeSymmetricKeyEncrypted(w io.Writer, rand io.Reader, passphrase []byte, cipherFunc CipherFunction) (key []byte, err os.Error) {
+ keySize := cipherFunc.KeySize()
+ if keySize == 0 {
+ return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
+ }
+
+ s2kBuf := new(bytes.Buffer)
+ keyEncryptingKey := make([]byte, keySize)
+ // s2k.Serialize salts and stretches the passphrase, and writes the
+ // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
+ err = s2k.Serialize(s2kBuf, keyEncryptingKey, rand, passphrase)
+ if err != nil {
+ return
+ }
+ s2kBytes := s2kBuf.Bytes()
+
+ packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
+ err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
+ if err != nil {
+ return
+ }
+
+ var buf [2]byte
+ buf[0] = symmetricKeyEncryptedVersion
+ buf[1] = byte(cipherFunc)
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ _, err = w.Write(s2kBytes)
+ if err != nil {
+ return
+ }
+
+ sessionKey := make([]byte, keySize)
+ _, err = io.ReadFull(rand, sessionKey)
+ if err != nil {
+ return
+ }
+ iv := make([]byte, cipherFunc.blockSize())
+ c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
+ encryptedCipherAndKey := make([]byte, keySize+1)
+ c.XORKeyStream(encryptedCipherAndKey, buf[1:])
+ c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
+ _, err = w.Write(encryptedCipherAndKey)
+ if err != nil {
+ return
+ }
+
+ key = sessionKey
+ return
+}
diff --git a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go
index 717c8ffa6d6..823ec400d40 100644
--- a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go
+++ b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go
@@ -6,6 +6,7 @@ package packet
import (
"bytes"
+ "crypto/rand"
"encoding/hex"
"io/ioutil"
"os"
@@ -60,3 +61,41 @@ func TestSymmetricKeyEncrypted(t *testing.T) {
const symmetricallyEncryptedHex = "8c0d04030302371a0b38d884f02060c91cf97c9973b8e58e028e9501708ccfe618fb92afef7fa2d80ddadd93cf"
const symmetricallyEncryptedContentsHex = "cb1062004d14c4df636f6e74656e74732e0a"
+
+func TestSerializeSymmetricKeyEncrypted(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ passphrase := []byte("testing")
+ cipherFunc := CipherAES128
+
+ key, err := SerializeSymmetricKeyEncrypted(buf, rand.Reader, passphrase, cipherFunc)
+ if err != nil {
+ t.Errorf("failed to serialize: %s", err)
+ return
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("failed to reparse: %s", err)
+ return
+ }
+ ske, ok := p.(*SymmetricKeyEncrypted)
+ if !ok {
+ t.Errorf("parsed a different packet type: %#v", p)
+ return
+ }
+
+ if !ske.Encrypted {
+ t.Errorf("SKE not encrypted but should be")
+ }
+ if ske.CipherFunc != cipherFunc {
+ t.Errorf("SKE cipher function is %d (expected %d)", ske.CipherFunc, cipherFunc)
+ }
+ err = ske.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("failed to decrypt reparsed SKE: %s", err)
+ return
+ }
+ if !bytes.Equal(key, ske.Key) {
+ t.Errorf("keys don't match after Decrpyt: %x (original) vs %x (parsed)", key, ske.Key)
+ }
+}
diff --git a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go
index fc19ffe809a..e33c9f3a060 100644
--- a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go
+++ b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go
@@ -7,6 +7,7 @@ package packet
import (
"crypto/cipher"
"crypto/openpgp/error"
+ "crypto/rand"
"crypto/sha1"
"crypto/subtle"
"hash"
@@ -24,6 +25,8 @@ type SymmetricallyEncrypted struct {
prefix []byte
}
+const symmetricallyEncryptedVersion = 1
+
func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
if se.MDC {
// See RFC 4880, section 5.13.
@@ -32,7 +35,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
if err != nil {
return err
}
- if buf[0] != 1 {
+ if buf[0] != symmetricallyEncryptedVersion {
return error.UnsupportedError("unknown SymmetricallyEncrypted version")
}
}
@@ -44,7 +47,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
// packet can be read. An incorrect key can, with high probability, be detected
// immediately and this will result in a KeyIncorrect error being returned.
func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, os.Error) {
- keySize := c.keySize()
+ keySize := c.KeySize()
if keySize == 0 {
return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
}
@@ -174,6 +177,9 @@ func (ser *seMDCReader) Read(buf []byte) (n int, err os.Error) {
return
}
+// This is a new-format packet tag byte for a type 19 (MDC) packet.
+const mdcPacketTagByte = byte(0x80) | 0x40 | 19
+
func (ser *seMDCReader) Close() os.Error {
if ser.error {
return error.SignatureError("error during reading")
@@ -191,16 +197,95 @@ func (ser *seMDCReader) Close() os.Error {
}
}
- // This is a new-format packet tag byte for a type 19 (MDC) packet.
- const mdcPacketTagByte = byte(0x80) | 0x40 | 19
if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
return error.SignatureError("MDC packet not found")
}
ser.h.Write(ser.trailer[:2])
final := ser.h.Sum()
- if subtle.ConstantTimeCompare(final, ser.trailer[2:]) == 1 {
+ if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
return error.SignatureError("hash mismatch")
}
return nil
}
+
+// An seMDCWriter writes through to an io.WriteCloser while maintains a running
+// hash of the data written. On close, it emits an MDC packet containing the
+// running hash.
+type seMDCWriter struct {
+ w io.WriteCloser
+ h hash.Hash
+}
+
+func (w *seMDCWriter) Write(buf []byte) (n int, err os.Error) {
+ w.h.Write(buf)
+ return w.w.Write(buf)
+}
+
+func (w *seMDCWriter) Close() (err os.Error) {
+ var buf [mdcTrailerSize]byte
+
+ buf[0] = mdcPacketTagByte
+ buf[1] = sha1.Size
+ w.h.Write(buf[:2])
+ digest := w.h.Sum()
+ copy(buf[2:], digest)
+
+ _, err = w.w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ return w.w.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err os.Error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() os.Error {
+ return nil
+}
+
+// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
+// to w and returns a WriteCloser to which the to-be-encrypted packets can be
+// written.
+func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte) (contents io.WriteCloser, err os.Error) {
+ if c.KeySize() != len(key) {
+ return nil, error.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
+ }
+ writeCloser := noOpCloser{w}
+ ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
+ if err != nil {
+ return
+ }
+
+ _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
+ if err != nil {
+ return
+ }
+
+ block := c.new(key)
+ blockSize := block.BlockSize()
+ iv := make([]byte, blockSize)
+ _, err = rand.Reader.Read(iv)
+ if err != nil {
+ return
+ }
+ s, prefix := cipher.NewOCFBEncrypter(block, iv, cipher.OCFBNoResync)
+ _, err = ciphertext.Write(prefix)
+ if err != nil {
+ return
+ }
+ plaintext := cipher.StreamWriter{S: s, W: ciphertext}
+
+ h := sha1.New()
+ h.Write(iv)
+ h.Write(iv[blockSize-2:])
+ contents = &seMDCWriter{w: plaintext, h: h}
+ return
+}
diff --git a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go
index 5543b20297a..1054fc2f91a 100644
--- a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go
+++ b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go
@@ -9,6 +9,7 @@ import (
"crypto/openpgp/error"
"crypto/sha1"
"encoding/hex"
+ "io"
"io/ioutil"
"os"
"testing"
@@ -76,3 +77,48 @@ func testMDCReader(t *testing.T) {
}
const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c849cb4c4de10200aff40b45d31432c80cb384299a0655966d6939dfdeed1dddf980"
+
+func TestSerialize(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ c := CipherAES128
+ key := make([]byte, c.KeySize())
+
+ w, err := SerializeSymmetricallyEncrypted(buf, c, key)
+ if err != nil {
+ t.Errorf("error from SerializeSymmetricallyEncrypted: %s", err)
+ return
+ }
+
+ contents := []byte("hello world\n")
+
+ w.Write(contents)
+ w.Close()
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+
+ se, ok := p.(*SymmetricallyEncrypted)
+ if !ok {
+ t.Errorf("didn't read a *SymmetricallyEncrypted")
+ return
+ }
+
+ r, err := se.Decrypt(c, key)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ contentsCopy := bytes.NewBuffer(nil)
+ _, err = io.Copy(contentsCopy, r)
+ if err != nil {
+ t.Errorf("error from io.Copy: %s", err)
+ return
+ }
+ if !bytes.Equal(contentsCopy.Bytes(), contents) {
+ t.Errorf("contents not equal got: %x want: %x", contentsCopy.Bytes(), contents)
+ }
+}
diff --git a/libgo/go/crypto/openpgp/packet/userid.go b/libgo/go/crypto/openpgp/packet/userid.go
index ed2ad777486..0580ba3edc0 100644
--- a/libgo/go/crypto/openpgp/packet/userid.go
+++ b/libgo/go/crypto/openpgp/packet/userid.go
@@ -20,6 +20,51 @@ type UserId struct {
Name, Comment, Email string
}
+func hasInvalidCharacters(s string) bool {
+ for _, c := range s {
+ switch c {
+ case '(', ')', '<', '>', 0:
+ return true
+ }
+ }
+ return false
+}
+
+// NewUserId returns a UserId or nil if any of the arguments contain invalid
+// characters. The invalid characters are '\x00', '(', ')', '<' and '>'
+func NewUserId(name, comment, email string) *UserId {
+ // RFC 4880 doesn't deal with the structure of userid strings; the
+ // name, comment and email form is just a convention. However, there's
+ // no convention about escaping the metacharacters and GPG just refuses
+ // to create user ids where, say, the name contains a '('. We mirror
+ // this behaviour.
+
+ if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
+ return nil
+ }
+
+ uid := new(UserId)
+ uid.Name, uid.Comment, uid.Email = name, comment, email
+ uid.Id = name
+ if len(comment) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "("
+ uid.Id += comment
+ uid.Id += ")"
+ }
+ if len(email) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "<"
+ uid.Id += email
+ uid.Id += ">"
+ }
+ return uid
+}
+
func (uid *UserId) parse(r io.Reader) (err os.Error) {
// RFC 4880, section 5.11
b, err := ioutil.ReadAll(r)
@@ -31,6 +76,17 @@ func (uid *UserId) parse(r io.Reader) (err os.Error) {
return
}
+// Serialize marshals uid to w in the form of an OpenPGP packet, including
+// header.
+func (uid *UserId) Serialize(w io.Writer) os.Error {
+ err := serializeHeader(w, packetTypeUserId, len(uid.Id))
+ if err != nil {
+ return err
+ }
+ _, err = w.Write([]byte(uid.Id))
+ return err
+}
+
// parseUserId extracts the name, comment and email from a user id string that
// is formatted as "Full Name (Comment) <email@example.com>".
func parseUserId(id string) (name, comment, email string) {
diff --git a/libgo/go/crypto/openpgp/packet/userid_test.go b/libgo/go/crypto/openpgp/packet/userid_test.go
index 394873dc38c..29681938938 100644
--- a/libgo/go/crypto/openpgp/packet/userid_test.go
+++ b/libgo/go/crypto/openpgp/packet/userid_test.go
@@ -40,3 +40,48 @@ func TestParseUserId(t *testing.T) {
}
}
}
+
+var newUserIdTests = []struct {
+ name, comment, email, id string
+}{
+ {"foo", "", "", "foo"},
+ {"", "bar", "", "(bar)"},
+ {"", "", "baz", "<baz>"},
+ {"foo", "bar", "", "foo (bar)"},
+ {"foo", "", "baz", "foo <baz>"},
+ {"", "bar", "baz", "(bar) <baz>"},
+ {"foo", "bar", "baz", "foo (bar) <baz>"},
+}
+
+func TestNewUserId(t *testing.T) {
+ for i, test := range newUserIdTests {
+ uid := NewUserId(test.name, test.comment, test.email)
+ if uid == nil {
+ t.Errorf("#%d: returned nil", i)
+ continue
+ }
+ if uid.Id != test.id {
+ t.Errorf("#%d: got '%s', want '%s'", i, uid.Id, test.id)
+ }
+ }
+}
+
+var invalidNewUserIdTests = []struct {
+ name, comment, email string
+}{
+ {"foo(", "", ""},
+ {"foo<", "", ""},
+ {"", "bar)", ""},
+ {"", "bar<", ""},
+ {"", "", "baz>"},
+ {"", "", "baz)"},
+ {"", "", "baz\x00"},
+}
+
+func TestNewUserIdWithInvalidInput(t *testing.T) {
+ for i, test := range invalidNewUserIdTests {
+ if uid := NewUserId(test.name, test.comment, test.email); uid != nil {
+ t.Errorf("#%d: returned non-nil value: %#v", i, uid)
+ }
+ }
+}
diff --git a/libgo/go/crypto/openpgp/read.go b/libgo/go/crypto/openpgp/read.go
index 4f84dff82bb..d95f613c62b 100644
--- a/libgo/go/crypto/openpgp/read.go
+++ b/libgo/go/crypto/openpgp/read.go
@@ -10,7 +10,6 @@ import (
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
- "crypto/rsa"
_ "crypto/sha256"
"hash"
"io"
@@ -44,7 +43,7 @@ type MessageDetails struct {
DecryptedWith Key // the private key used to decrypt the message, if any.
IsSigned bool // true if the message is signed.
SignedByKeyId uint64 // the key id of the signer, if any.
- SignedBy *Key // the key of the signer, if availible.
+ SignedBy *Key // the key of the signer, if available.
LiteralData *packet.LiteralData // the metadata of the contents
UnverifiedBody io.Reader // the contents of the message.
@@ -57,7 +56,6 @@ type MessageDetails struct {
// been consumed. Once EOF has been seen, the following fields are
// valid. (An authentication code failure is reported as a
// SignatureError error when reading from UnverifiedBody.)
-
SignatureError os.Error // nil if the signature is good.
Signature *packet.Signature // the signature packet itself.
@@ -112,7 +110,10 @@ ParsePackets:
case *packet.EncryptedKey:
// This packet contains the decryption key encrypted to a public key.
md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
- if p.Algo != packet.PubKeyAlgoRSA && p.Algo != packet.PubKeyAlgoRSAEncryptOnly {
+ switch p.Algo {
+ case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
+ break
+ default:
continue
}
var keys []Key
@@ -145,7 +146,7 @@ ParsePackets:
// function so that it can decrypt a key or give us a passphrase.
FindKey:
for {
- // See if any of the keys already have a private key availible
+ // See if any of the keys already have a private key available
candidates = candidates[:0]
candidateFingerprints := make(map[string]bool)
@@ -155,7 +156,7 @@ FindKey:
}
if !pk.key.PrivateKey.Encrypted {
if len(pk.encryptedKey.Key) == 0 {
- pk.encryptedKey.DecryptRSA(pk.key.PrivateKey.PrivateKey.(*rsa.PrivateKey))
+ pk.encryptedKey.Decrypt(pk.key.PrivateKey)
}
if len(pk.encryptedKey.Key) == 0 {
continue
@@ -214,7 +215,7 @@ FindKey:
return readSignedMessage(packets, md, keyring)
}
-// readSignedMessage reads a possibily signed message if mdin is non-zero then
+// readSignedMessage reads a possibly signed message if mdin is non-zero then
// that structure is updated and returned. Otherwise a fresh MessageDetails is
// used.
func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err os.Error) {
@@ -249,11 +250,12 @@ FindLiteralData:
md.IsSigned = true
md.SignedByKeyId = p.KeyId
keys := keyring.KeysById(p.KeyId)
- for _, key := range keys {
+ for i, key := range keys {
if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign {
continue
}
- md.SignedBy = &key
+ md.SignedBy = &keys[i]
+ break
}
case *packet.LiteralData:
md.LiteralData = p
@@ -274,13 +276,13 @@ FindLiteralData:
// hashForSignature returns a pair of hashes that can be used to verify a
// signature. The signature may specify that the contents of the signed message
-// should be preprocessed (i.e. to normalise line endings). Thus this function
+// should be preprocessed (i.e. to normalize line endings). Thus this function
// returns two hashes. The second should be used to hash the message itself and
// performs any needed preprocessing.
func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, os.Error) {
h := hashId.New()
if h == nil {
- return nil, nil, error.UnsupportedError("hash not availible: " + strconv.Itoa(int(hashId)))
+ return nil, nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId)))
}
switch sigType {
diff --git a/libgo/go/crypto/openpgp/read_test.go b/libgo/go/crypto/openpgp/read_test.go
index 423c85b0f27..4dc290ef29d 100644
--- a/libgo/go/crypto/openpgp/read_test.go
+++ b/libgo/go/crypto/openpgp/read_test.go
@@ -33,6 +33,29 @@ func TestReadKeyRing(t *testing.T) {
}
}
+func TestRereadKeyRing(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ if err != nil {
+ t.Errorf("error in initial parse: %s", err)
+ return
+ }
+ out := new(bytes.Buffer)
+ err = kring[0].Serialize(out)
+ if err != nil {
+ t.Errorf("error in serialization: %s", err)
+ return
+ }
+ kring, err = ReadKeyRing(out)
+ if err != nil {
+ t.Errorf("error in second parse: %s", err)
+ return
+ }
+
+ if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB {
+ t.Errorf("bad keyring: %#v", kring)
+ }
+}
+
func TestReadPrivateKeyRing(t *testing.T) {
kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
if err != nil {
@@ -102,49 +125,71 @@ func TestTextSignedMessage(t *testing.T) {
checkSignedMessage(t, signedTextMessageHex, signedTextInput)
}
-func TestSignedEncryptedMessage(t *testing.T) {
- expected := "Signed and encrypted message\n"
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
- prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
- if symmetric {
- t.Errorf("prompt: message was marked as symmetrically encrypted")
- return nil, error.KeyIncorrectError
- }
+var signedEncryptedMessageTests = []struct {
+ keyRingHex string
+ messageHex string
+ signedByKeyId uint64
+ encryptedToKeyId uint64
+}{
+ {
+ testKeys1And2PrivateHex,
+ signedEncryptedMessageHex,
+ 0xa34d7e18c20c31bb,
+ 0x2a67d68660df41c7,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ signedEncryptedMessage2Hex,
+ 0x33af447ccd759b09,
+ 0xcf6a7abcd43e3673,
+ },
+}
- if len(keys) == 0 {
- t.Error("prompt: no keys requested")
- return nil, error.KeyIncorrectError
+func TestSignedEncryptedMessage(t *testing.T) {
+ for i, test := range signedEncryptedMessageTests {
+ expected := "Signed and encrypted message\n"
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+ prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
+ if symmetric {
+ t.Errorf("prompt: message was marked as symmetrically encrypted")
+ return nil, error.KeyIncorrectError
+ }
+
+ if len(keys) == 0 {
+ t.Error("prompt: no keys requested")
+ return nil, error.KeyIncorrectError
+ }
+
+ err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+ if err != nil {
+ t.Errorf("prompt: error decrypting key: %s", err)
+ return nil, error.KeyIncorrectError
+ }
+
+ return nil, nil
}
- err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+ md, err := ReadMessage(readerFromHex(test.messageHex), kring, prompt)
if err != nil {
- t.Errorf("prompt: error decrypting key: %s", err)
- return nil, error.KeyIncorrectError
+ t.Errorf("#%d: error reading message: %s", i, err)
+ return
}
- return nil, nil
- }
-
- md, err := ReadMessage(readerFromHex(signedEncryptedMessageHex), kring, prompt)
- if err != nil {
- t.Errorf("error reading message: %s", err)
- return
- }
-
- if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != 0x2a67d68660df41c7 {
- t.Errorf("bad MessageDetails: %#v", md)
- }
+ if !md.IsSigned || md.SignedByKeyId != test.signedByKeyId || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != test.encryptedToKeyId {
+ t.Errorf("#%d: bad MessageDetails: %#v", i, md)
+ }
- contents, err := ioutil.ReadAll(md.UnverifiedBody)
- if err != nil {
- t.Errorf("error reading UnverifiedBody: %s", err)
- }
- if string(contents) != expected {
- t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
- }
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading UnverifiedBody: %s", i, err)
+ }
+ if string(contents) != expected {
+ t.Errorf("#%d: bad UnverifiedBody got:%s want:%s", i, string(contents), expected)
+ }
- if md.SignatureError != nil || md.Signature == nil {
- t.Errorf("failed to validate: %s", md.SignatureError)
+ if md.SignatureError != nil || md.Signature == nil {
+ t.Errorf("#%d: failed to validate: %s", i, md.SignatureError)
+ }
}
}
@@ -193,9 +238,9 @@ func TestSymmetricallyEncrypted(t *testing.T) {
t.Errorf("ReadAll: %s", err)
}
- expectedCreatationTime := uint32(1295992998)
- if md.LiteralData.Time != expectedCreatationTime {
- t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreatationTime)
+ expectedCreationTime := uint32(1295992998)
+ if md.LiteralData.Time != expectedCreationTime {
+ t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreationTime)
}
if string(contents) != expected {
@@ -265,12 +310,16 @@ const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d1
const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
+const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
+
const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d"
+const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3"
+
const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6"
const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
diff --git a/libgo/go/crypto/openpgp/s2k/s2k.go b/libgo/go/crypto/openpgp/s2k/s2k.go
index 93b7582fa06..da926a76ed2 100644
--- a/libgo/go/crypto/openpgp/s2k/s2k.go
+++ b/libgo/go/crypto/openpgp/s2k/s2k.go
@@ -90,7 +90,7 @@ func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
}
h := hash.New()
if h == nil {
- return nil, error.UnsupportedError("hash not availible: " + strconv.Itoa(int(hash)))
+ return nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
}
switch buf[0] {
@@ -123,6 +123,26 @@ func Parse(r io.Reader) (f func(out, in []byte), err os.Error) {
return nil, error.UnsupportedError("S2K function")
}
+// Serialize salts and stretches the given passphrase and writes the resulting
+// key into key. It also serializes an S2K descriptor to w.
+func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) os.Error {
+ var buf [11]byte
+ buf[0] = 3 /* iterated and salted */
+ buf[1], _ = HashToHashId(crypto.SHA1)
+ salt := buf[2:10]
+ if _, err := io.ReadFull(rand, salt); err != nil {
+ return err
+ }
+ const count = 65536 // this is the default in gpg
+ buf[10] = 96 // 65536 iterations
+ if _, err := w.Write(buf[:]); err != nil {
+ return err
+ }
+
+ Iterated(key, crypto.SHA1.New(), passphrase, salt, count)
+ return nil
+}
+
// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
// Go's crypto.Hash type. See RFC 4880, section 9.4.
var hashToHashIdMapping = []struct {
diff --git a/libgo/go/crypto/openpgp/s2k/s2k_test.go b/libgo/go/crypto/openpgp/s2k/s2k_test.go
index 75bc47ec10b..ec4012c2384 100644
--- a/libgo/go/crypto/openpgp/s2k/s2k_test.go
+++ b/libgo/go/crypto/openpgp/s2k/s2k_test.go
@@ -7,6 +7,7 @@ package s2k
import (
"bytes"
"crypto/sha1"
+ "crypto/rand"
"encoding/hex"
"testing"
)
@@ -36,7 +37,6 @@ func TestSalted(t *testing.T) {
}
}
-
var iteratedTests = []struct {
in, out string
}{
@@ -62,7 +62,6 @@ func TestIterated(t *testing.T) {
}
}
-
var parseTests = []struct {
spec, in, out string
}{
@@ -95,3 +94,25 @@ func TestParse(t *testing.T) {
}
}
}
+
+func TestSerialize(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ key := make([]byte, 16)
+ passphrase := []byte("testing")
+ err := Serialize(buf, key, rand.Reader, passphrase)
+ if err != nil {
+ t.Errorf("failed to serialize: %s", err)
+ return
+ }
+
+ f, err := Parse(buf)
+ if err != nil {
+ t.Errorf("failed to reparse: %s", err)
+ return
+ }
+ key2 := make([]byte, len(key))
+ f(key2, passphrase)
+ if !bytes.Equal(key2, key) {
+ t.Errorf("keys don't match: %x (serialied) vs %x (parsed)", key, key2)
+ }
+}
diff --git a/libgo/go/crypto/openpgp/write.go b/libgo/go/crypto/openpgp/write.go
index ef7b11230a9..9884472ce75 100644
--- a/libgo/go/crypto/openpgp/write.go
+++ b/libgo/go/crypto/openpgp/write.go
@@ -6,12 +6,13 @@ package openpgp
import (
"crypto"
- "crypto/dsa"
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
- "crypto/rsa"
+ "crypto/openpgp/s2k"
+ "crypto/rand"
_ "crypto/sha256"
+ "hash"
"io"
"os"
"strconv"
@@ -77,20 +78,231 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S
}
io.Copy(wrappedHash, message)
- switch signer.PrivateKey.PubKeyAlgo {
- case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSASignOnly:
- priv := signer.PrivateKey.PrivateKey.(*rsa.PrivateKey)
- err = sig.SignRSA(h, priv)
- case packet.PubKeyAlgoDSA:
- priv := signer.PrivateKey.PrivateKey.(*dsa.PrivateKey)
- err = sig.SignDSA(h, priv)
- default:
- err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ err = sig.Sign(h, signer.PrivateKey)
+ if err != nil {
+ return
+ }
+
+ return sig.Serialize(w)
+}
+
+// FileHints contains metadata about encrypted files. This metadata is, itself,
+// encrypted.
+type FileHints struct {
+ // IsBinary can be set to hint that the contents are binary data.
+ IsBinary bool
+ // FileName hints at the name of the file that should be written. It's
+ // truncated to 255 bytes if longer. It may be empty to suggest that the
+ // file should not be written to disk. It may be equal to "_CONSOLE" to
+ // suggest the data should not be written to disk.
+ FileName string
+ // EpochSeconds contains the modification time of the file, or 0 if not applicable.
+ EpochSeconds uint32
+}
+
+// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
+// The resulting WriteCloser must be closed after the contents of the file have
+// been written.
+func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
+ if hints == nil {
+ hints = &FileHints{}
}
+ key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, rand.Reader, passphrase, packet.CipherAES128)
if err != nil {
return
}
+ w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, packet.CipherAES128, key)
+ if err != nil {
+ return
+ }
+ return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+}
- return sig.Serialize(w)
+// intersectPreferences mutates and returns a prefix of a that contains only
+// the values in the intersection of a and b. The order of a is preserved.
+func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
+ var j int
+ for _, v := range a {
+ for _, v2 := range b {
+ if v == v2 {
+ a[j] = v
+ j++
+ break
+ }
+ }
+ }
+
+ return a[:j]
+}
+
+func hashToHashId(h crypto.Hash) uint8 {
+ v, ok := s2k.HashToHashId(h)
+ if !ok {
+ panic("tried to convert unknown hash")
+ }
+ return v
+}
+
+// Encrypt encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
+ var signer *packet.PrivateKey
+ if signed != nil {
+ signer = signed.signingKey().PrivateKey
+ if signer == nil || signer.Encrypted {
+ return nil, error.InvalidArgumentError("signing key must be decrypted")
+ }
+ }
+
+ // These are the possible ciphers that we'll use for the message.
+ candidateCiphers := []uint8{
+ uint8(packet.CipherAES128),
+ uint8(packet.CipherAES256),
+ uint8(packet.CipherCAST5),
+ }
+ // These are the possible hash functions that we'll use for the signature.
+ candidateHashes := []uint8{
+ hashToHashId(crypto.SHA256),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA1),
+ hashToHashId(crypto.RIPEMD160),
+ }
+ // In the event that a recipient doesn't specify any supported ciphers
+ // or hash functions, these are the ones that we assume that every
+ // implementation supports.
+ defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
+ defaultHashes := candidateHashes[len(candidateHashes)-1:]
+
+ encryptKeys := make([]Key, len(to))
+ for i := range to {
+ encryptKeys[i] = to[i].encryptionKey()
+ if encryptKeys[i].PublicKey == nil {
+ return nil, error.InvalidArgumentError("cannot encrypt a message to key id " + strconv.Uitob64(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
+ }
+
+ sig := to[i].primaryIdentity().SelfSignature
+
+ preferredSymmetric := sig.PreferredSymmetric
+ if len(preferredSymmetric) == 0 {
+ preferredSymmetric = defaultCiphers
+ }
+ preferredHashes := sig.PreferredHash
+ if len(preferredHashes) == 0 {
+ preferredHashes = defaultHashes
+ }
+ candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
+ candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
+ }
+
+ if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
+ return nil, error.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
+ }
+
+ cipher := packet.CipherFunction(candidateCiphers[0])
+ hash, _ := s2k.HashIdToHash(candidateHashes[0])
+ symKey := make([]byte, cipher.KeySize())
+ if _, err := io.ReadFull(rand.Reader, symKey); err != nil {
+ return nil, err
+ }
+
+ for _, key := range encryptKeys {
+ if err := packet.SerializeEncryptedKey(ciphertext, rand.Reader, key.PublicKey, cipher, symKey); err != nil {
+ return nil, err
+ }
+ }
+
+ encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey)
+ if err != nil {
+ return
+ }
+
+ if signer != nil {
+ ops := &packet.OnePassSignature{
+ SigType: packet.SigTypeBinary,
+ Hash: hash,
+ PubKeyAlgo: signer.PubKeyAlgo,
+ KeyId: signer.KeyId,
+ IsLast: true,
+ }
+ if err := ops.Serialize(encryptedData); err != nil {
+ return nil, err
+ }
+ }
+
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ w := encryptedData
+ if signer != nil {
+ // If we need to write a signature packet after the literal
+ // data then we need to stop literalData from closing
+ // encryptedData.
+ w = noOpCloser{encryptedData}
+
+ }
+ literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+ if err != nil {
+ return nil, err
+ }
+
+ if signer != nil {
+ return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil
+ }
+ return literalData, nil
+}
+
+// signatureWriter hashes the contents of a message while passing it along to
+// literalData. When closed, it closes literalData, writes a signature packet
+// to encryptedData and then also closes encryptedData.
+type signatureWriter struct {
+ encryptedData io.WriteCloser
+ literalData io.WriteCloser
+ hashType crypto.Hash
+ h hash.Hash
+ signer *packet.PrivateKey
+}
+
+func (s signatureWriter) Write(data []byte) (int, os.Error) {
+ s.h.Write(data)
+ return s.literalData.Write(data)
+}
+
+func (s signatureWriter) Close() os.Error {
+ sig := &packet.Signature{
+ SigType: packet.SigTypeBinary,
+ PubKeyAlgo: s.signer.PubKeyAlgo,
+ Hash: s.hashType,
+ CreationTime: uint32(time.Seconds()),
+ IssuerKeyId: &s.signer.KeyId,
+ }
+
+ if err := sig.Sign(s.h, s.signer); err != nil {
+ return err
+ }
+ if err := s.literalData.Close(); err != nil {
+ return err
+ }
+ if err := sig.Serialize(s.encryptedData); err != nil {
+ return err
+ }
+ return s.encryptedData.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+// TODO: we have two of these in OpenPGP packages alone. This probably needs
+// to be promoted somewhere more common.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err os.Error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() os.Error {
+ return nil
}
diff --git a/libgo/go/crypto/openpgp/write_test.go b/libgo/go/crypto/openpgp/write_test.go
index 42cd0d27f85..c542dfa45d8 100644
--- a/libgo/go/crypto/openpgp/write_test.go
+++ b/libgo/go/crypto/openpgp/write_test.go
@@ -6,7 +6,12 @@ package openpgp
import (
"bytes"
+ "crypto/rand"
+ "os"
+ "io"
+ "io/ioutil"
"testing"
+ "time"
)
func TestSignDetached(t *testing.T) {
@@ -44,3 +49,185 @@ func TestSignDetachedDSA(t *testing.T) {
testDetachedSignature(t, kring, out, signedInput, "check", testKey3KeyId)
}
+
+func TestNewEntity(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ e, err := NewEntity(rand.Reader, time.Seconds(), "Test User", "test", "test@example.com")
+ if err != nil {
+ t.Errorf("failed to create entity: %s", err)
+ return
+ }
+
+ w := bytes.NewBuffer(nil)
+ if err := e.SerializePrivate(w); err != nil {
+ t.Errorf("failed to serialize entity: %s", err)
+ return
+ }
+ serialized := w.Bytes()
+
+ el, err := ReadKeyRing(w)
+ if err != nil {
+ t.Errorf("failed to reparse entity: %s", err)
+ return
+ }
+
+ if len(el) != 1 {
+ t.Errorf("wrong number of entities found, got %d, want 1", len(el))
+ }
+
+ w = bytes.NewBuffer(nil)
+ if err := e.SerializePrivate(w); err != nil {
+ t.Errorf("failed to serialize entity second time: %s", err)
+ return
+ }
+
+ if !bytes.Equal(w.Bytes(), serialized) {
+ t.Errorf("results differed")
+ }
+}
+
+func TestSymmetricEncryption(t *testing.T) {
+ buf := new(bytes.Buffer)
+ plaintext, err := SymmetricallyEncrypt(buf, []byte("testing"), nil)
+ if err != nil {
+ t.Errorf("error writing headers: %s", err)
+ return
+ }
+ message := []byte("hello world\n")
+ _, err = plaintext.Write(message)
+ if err != nil {
+ t.Errorf("error writing to plaintext writer: %s", err)
+ }
+ err = plaintext.Close()
+ if err != nil {
+ t.Errorf("error closing plaintext writer: %s", err)
+ }
+
+ md, err := ReadMessage(buf, nil, func(keys []Key, symmetric bool) ([]byte, os.Error) {
+ return []byte("testing"), nil
+ })
+ if err != nil {
+ t.Errorf("error rereading message: %s", err)
+ }
+ messageBuf := bytes.NewBuffer(nil)
+ _, err = io.Copy(messageBuf, md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("error rereading message: %s", err)
+ }
+ if !bytes.Equal(message, messageBuf.Bytes()) {
+ t.Errorf("recovered message incorrect got '%s', want '%s'", messageBuf.Bytes(), message)
+ }
+}
+
+var testEncryptionTests = []struct {
+ keyRingHex string
+ isSigned bool
+}{
+ {
+ testKeys1And2PrivateHex,
+ false,
+ },
+ {
+ testKeys1And2PrivateHex,
+ true,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ false,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ true,
+ },
+}
+
+func TestEncryption(t *testing.T) {
+ for i, test := range testEncryptionTests {
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+
+ passphrase := []byte("passphrase")
+ for _, entity := range kring {
+ if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
+ err := entity.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt key", i)
+ }
+ }
+ for _, subkey := range entity.Subkeys {
+ if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted {
+ err := subkey.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt subkey", i)
+ }
+ }
+ }
+ }
+
+ var signed *Entity
+ if test.isSigned {
+ signed = kring[0]
+ }
+
+ buf := new(bytes.Buffer)
+ w, err := Encrypt(buf, kring[:1], signed, nil /* no hints */ )
+ if err != nil {
+ t.Errorf("#%d: error in Encrypt: %s", i, err)
+ continue
+ }
+
+ const message = "testing"
+ _, err = w.Write([]byte(message))
+ if err != nil {
+ t.Errorf("#%d: error writing plaintext: %s", i, err)
+ continue
+ }
+ err = w.Close()
+ if err != nil {
+ t.Errorf("#%d: error closing WriteCloser: %s", i, err)
+ continue
+ }
+
+ md, err := ReadMessage(buf, kring, nil /* no prompt */ )
+ if err != nil {
+ t.Errorf("#%d: error reading message: %s", i, err)
+ continue
+ }
+
+ if test.isSigned {
+ expectedKeyId := kring[0].signingKey().PublicKey.KeyId
+ if md.SignedByKeyId != expectedKeyId {
+ t.Errorf("#%d: message signed by wrong key id, got: %d, want: %d", i, *md.SignedBy, expectedKeyId)
+ }
+ if md.SignedBy == nil {
+ t.Errorf("#%d: failed to find the signing Entity", i)
+ }
+ }
+
+ plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading encrypted contents: %s", i, err)
+ continue
+ }
+
+ expectedKeyId := kring[0].encryptionKey().PublicKey.KeyId
+ if len(md.EncryptedToKeyIds) != 1 || md.EncryptedToKeyIds[0] != expectedKeyId {
+ t.Errorf("#%d: expected message to be encrypted to %v, but got %#v", i, expectedKeyId, md.EncryptedToKeyIds)
+ }
+
+ if string(plaintext) != message {
+ t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message)
+ }
+
+ if test.isSigned {
+ if md.SignatureError != nil {
+ t.Errorf("#%d: signature error: %s", i, err)
+ }
+ if md.Signature == nil {
+ t.Error("signature missing")
+ }
+ }
+ }
+}
diff --git a/libgo/go/crypto/rand/rand_windows.go b/libgo/go/crypto/rand/rand_windows.go
index 281d6dc6aaf..0eab6b213a0 100644
--- a/libgo/go/crypto/rand/rand_windows.go
+++ b/libgo/go/crypto/rand/rand_windows.go
@@ -19,7 +19,7 @@ func init() { Reader = &rngReader{} }
// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
type rngReader struct {
- prov uint32
+ prov syscall.Handle
mu sync.Mutex
}
diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go
new file mode 100644
index 00000000000..77028476e4f
--- /dev/null
+++ b/libgo/go/crypto/rand/util.go
@@ -0,0 +1,80 @@
+// 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 rand
+
+import (
+ "big"
+ "io"
+ "os"
+)
+
+// Prime returns a number, p, of the given size, such that p is prime
+// with high probability.
+func Prime(rand io.Reader, bits int) (p *big.Int, err os.Error) {
+ if bits < 1 {
+ err = os.EINVAL
+ }
+
+ b := uint(bits % 8)
+ if b == 0 {
+ b = 8
+ }
+
+ bytes := make([]byte, (bits+7)/8)
+ p = new(big.Int)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Clear bits in the first byte to make sure the candidate has a size <= bits.
+ bytes[0] &= uint8(int(1<<b) - 1)
+ // Don't let the value be too small, i.e, set the most significant bit.
+ bytes[0] |= 1 << (b - 1)
+ // 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
+}
+
+// Int returns a uniform random value in [0, max).
+func Int(rand io.Reader, max *big.Int) (n *big.Int, err os.Error) {
+ k := (max.BitLen() + 7) / 8
+
+ // b is the number of bits in the most significant byte of max.
+ b := uint(max.BitLen() % 8)
+ if b == 0 {
+ b = 8
+ }
+
+ bytes := make([]byte, k)
+ n = new(big.Int)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Clear bits in the first byte to increase the probability
+ // that the candidate is < max.
+ bytes[0] &= uint8(int(1<<b) - 1)
+
+ n.SetBytes(bytes)
+ if n.Cmp(max) < 0 {
+ return
+ }
+ }
+
+ return
+}
diff --git a/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go
index 3defa62ea6d..6006231145a 100644
--- a/libgo/go/crypto/rsa/pkcs1v15.go
+++ b/libgo/go/crypto/rsa/pkcs1v15.go
@@ -232,11 +232,11 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
hashLen = hash.Size()
if inLen != hashLen {
- return 0, nil, os.ErrorString("input must be hashed message")
+ return 0, nil, os.NewError("input must be hashed message")
}
prefix, ok := hashPrefixes[hash]
if !ok {
- return 0, nil, os.ErrorString("unsupported hash function")
+ return 0, nil, os.NewError("unsupported hash function")
}
return
}
diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go
index e1813dbf938..6957659f284 100644
--- a/libgo/go/crypto/rsa/rsa.go
+++ b/libgo/go/crypto/rsa/rsa.go
@@ -9,6 +9,7 @@ package rsa
import (
"big"
+ "crypto/rand"
"crypto/subtle"
"hash"
"io"
@@ -18,69 +19,6 @@ import (
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
@@ -94,7 +32,7 @@ type PrivateKey struct {
Primes []*big.Int // prime factors of N, has >= 2 elements.
// Precomputed contains precomputed values that speed up private
- // operations, if availible.
+ // operations, if available.
Precomputed PrecomputedValues
}
@@ -126,7 +64,7 @@ func (priv *PrivateKey) Validate() os.Error {
// easy for an attack to generate composites that pass this test.
for _, prime := range priv.Primes {
if !big.ProbablyPrime(prime, 20) {
- return os.ErrorString("Prime factor is composite")
+ return os.NewError("prime factor is composite")
}
}
@@ -136,7 +74,7 @@ func (priv *PrivateKey) Validate() os.Error {
modulus.Mul(modulus, prime)
}
if modulus.Cmp(priv.N) != 0 {
- return os.ErrorString("invalid modulus")
+ return os.NewError("invalid modulus")
}
// Check that e and totient(Πprimes) are coprime.
totient := new(big.Int).Set(bigOne)
@@ -150,20 +88,20 @@ func (priv *PrivateKey) Validate() os.Error {
y := new(big.Int)
big.GcdInt(gcd, x, y, totient, e)
if gcd.Cmp(bigOne) != 0 {
- return os.ErrorString("invalid public exponent E")
+ return os.NewError("invalid public exponent E")
}
// Check that de ≡ 1 (mod totient(Πprimes))
de := new(big.Int).Mul(priv.D, e)
de.Mod(de, totient)
if de.Cmp(bigOne) != 0 {
- return os.ErrorString("invalid private exponent D")
+ return os.NewError("invalid private exponent D")
}
return nil
}
// GenerateKey generates an RSA keypair of the given bit size.
-func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
- return GenerateMultiPrimeKey(rand, 2, bits)
+func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err os.Error) {
+ return GenerateMultiPrimeKey(random, 2, bits)
}
// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
@@ -176,7 +114,7 @@ func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) {
//
// [1] US patent 4405829 (1972, expired)
// [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
-func GenerateMultiPrimeKey(rand io.Reader, nprimes int, bits int) (priv *PrivateKey, err os.Error) {
+func GenerateMultiPrimeKey(random io.Reader, nprimes int, 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
@@ -189,7 +127,7 @@ func GenerateMultiPrimeKey(rand io.Reader, nprimes int, bits int) (priv *Private
priv.E = 3
if nprimes < 2 {
- return nil, os.ErrorString("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
+ return nil, os.NewError("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
}
primes := make([]*big.Int, nprimes)
@@ -198,7 +136,7 @@ NextSetOfPrimes:
for {
todo := bits
for i := 0; i < nprimes; i++ {
- primes[i], err = randomPrime(rand, todo/(nprimes-i))
+ primes[i], err = rand.Prime(random, todo/(nprimes-i))
if err != nil {
return nil, err
}
@@ -293,7 +231,7 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
// 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) {
+func EncryptOAEP(hash hash.Hash, random 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 {
@@ -313,7 +251,7 @@ func EncryptOAEP(hash hash.Hash, rand io.Reader, pub *PublicKey, msg []byte, lab
db[len(db)-len(msg)-1] = 1
copy(db[len(db)-len(msg):], msg)
- _, err = io.ReadFull(rand, seed)
+ _, err = io.ReadFull(random, seed)
if err != nil {
return
}
@@ -405,7 +343,7 @@ func (priv *PrivateKey) Precompute() {
// 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) {
+func decrypt(random 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{}
@@ -413,16 +351,16 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E
}
var ir *big.Int
- if rand != nil {
+ if random != 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.
+ // by multiplying by the multiplicative inverse of r.
var r *big.Int
for {
- r, err = randomNumber(rand, priv.N)
+ r, err = rand.Int(random, priv.N)
if err != nil {
return
}
@@ -483,7 +421,7 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E
// 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) {
+func DecryptOAEP(hash hash.Hash, random 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 {
@@ -493,7 +431,7 @@ func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []
c := new(big.Int).SetBytes(ciphertext)
- m, err := decrypt(rand, priv, c)
+ m, err := decrypt(random, priv, c)
if err != nil {
return
}
diff --git a/libgo/go/crypto/subtle/constant_time_test.go b/libgo/go/crypto/subtle/constant_time_test.go
index b28b7358105..adab8e2e8dd 100644
--- a/libgo/go/crypto/subtle/constant_time_test.go
+++ b/libgo/go/crypto/subtle/constant_time_test.go
@@ -14,14 +14,14 @@ type TestConstantTimeCompareStruct struct {
out int
}
-var testConstandTimeCompareData = []TestConstantTimeCompareStruct{
+var testConstantTimeCompareData = []TestConstantTimeCompareStruct{
{[]byte{}, []byte{}, 1},
{[]byte{0x11}, []byte{0x11}, 1},
{[]byte{0x12}, []byte{0x11}, 0},
}
func TestConstantTimeCompare(t *testing.T) {
- for i, test := range testConstandTimeCompareData {
+ for i, test := range testConstantTimeCompareData {
if r := ConstantTimeCompare(test.a, test.b); r != test.out {
t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
}
diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go
index 0b26aae84d1..3efac9c13b0 100644
--- a/libgo/go/crypto/tls/common.go
+++ b/libgo/go/crypto/tls/common.go
@@ -87,7 +87,7 @@ 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
+ certTypeDSSFixedDH = 4 // A certificate containing a static DH key
// Rest of these are reserved by the TLS spec
)
diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go
index 48d3f725b49..fac65afd9cf 100644
--- a/libgo/go/crypto/tls/conn.go
+++ b/libgo/go/crypto/tls/conn.go
@@ -34,7 +34,7 @@ type Conn struct {
cipherSuite uint16
ocspResponse []byte // stapled OCSP response
peerCertificates []*x509.Certificate
- // verifedChains contains the certificate chains that we built, as
+ // verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
@@ -237,7 +237,7 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
// "Password Interception in a SSL/TLS Channel", Brice
// Canvel et al.
//
- // However, our behaviour matches OpenSSL, so we leak
+ // However, our behavior matches OpenSSL, so we leak
// only as much as they do.
default:
panic("unknown cipher type")
@@ -410,7 +410,7 @@ func (hc *halfConn) freeBlock(b *block) {
// 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.
+// block with the remainder. the latter may be nil.
func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
if len(b.data) <= n {
return b, nil
@@ -790,10 +790,10 @@ func (c *Conn) VerifyHostname(host string) os.Error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if !c.isClient {
- return os.ErrorString("VerifyHostname called on TLS server connection")
+ return os.NewError("VerifyHostname called on TLS server connection")
}
if !c.handshakeComplete {
- return os.ErrorString("TLS handshake has not yet been performed")
+ return os.NewError("TLS handshake has not yet been performed")
}
return c.peerCertificates[0].VerifyHostname(host)
}
diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go
index 5b8c700e5f9..41206e276b3 100644
--- a/libgo/go/crypto/tls/generate_cert.go
+++ b/libgo/go/crypto/tls/generate_cert.go
@@ -8,8 +8,10 @@
package main
import (
- "crypto/rsa"
+ "big"
+ "crypto/x509/pkix"
"crypto/rand"
+ "crypto/rsa"
"crypto/x509"
"encoding/pem"
"flag"
@@ -32,8 +34,8 @@ func main() {
now := time.Seconds()
template := x509.Certificate{
- SerialNumber: []byte{0},
- Subject: x509.Name{
+ SerialNumber: new(big.Int).SetInt64(0),
+ Subject: pkix.Name{
CommonName: *hostName,
Organization: []string{"Acme Co"},
},
@@ -59,7 +61,7 @@ func main() {
certOut.Close()
log.Print("written cert.pem\n")
- keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0600)
+ keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
log.Print("failed to open key.pem for writing:", err)
return
diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go
index c758c96d4ef..15604cea7ea 100644
--- a/libgo/go/crypto/tls/handshake_client.go
+++ b/libgo/go/crypto/tls/handshake_client.go
@@ -40,7 +40,7 @@ func (c *Conn) clientHandshake() os.Error {
_, err := io.ReadFull(c.config.rand(), hello.random[4:])
if err != nil {
c.sendAlert(alertInternalError)
- return os.ErrorString("short read from Rand")
+ return os.NewError("short read from Rand")
}
finishedHash.Write(hello.marshal())
@@ -69,7 +69,7 @@ func (c *Conn) clientHandshake() os.Error {
if !hello.nextProtoNeg && serverHello.nextProtoNeg {
c.sendAlert(alertHandshakeFailure)
- return os.ErrorString("server advertised unrequested NPN")
+ return os.NewError("server advertised unrequested NPN")
}
suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
@@ -92,7 +92,7 @@ func (c *Conn) clientHandshake() os.Error {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("failed to parse certificate from server: " + err.String())
+ return os.NewError("failed to parse certificate from server: " + err.String())
}
certs[i] = cert
}
diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go
index 37c8d154ac4..44a32404148 100644
--- a/libgo/go/crypto/tls/handshake_server.go
+++ b/libgo/go/crypto/tls/handshake_server.go
@@ -173,7 +173,7 @@ FindCipherSuite:
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not parse client's certificate: " + err.String())
+ return os.NewError("could not parse client's certificate: " + err.String())
}
certs[i] = cert
}
@@ -182,7 +182,7 @@ FindCipherSuite:
for i := 1; i < len(certs); i++ {
if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not validate certificate signature: " + err.String())
+ return os.NewError("could not validate certificate signature: " + err.String())
}
}
@@ -209,10 +209,10 @@ FindCipherSuite:
// 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
+ // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceding
// 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.
+ // possession of the private key of the certificate.
if len(c.peerCertificates) > 0 {
msg, err = c.readHandshake()
if err != nil {
@@ -229,7 +229,7 @@ FindCipherSuite:
err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not validate signature of connection nonces: " + err.String())
+ return os.NewError("could not validate signature of connection nonces: " + err.String())
}
finishedHash.Write(certVerify.marshal())
diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go
index 5a1e754dcf5..b77646e4383 100644
--- a/libgo/go/crypto/tls/handshake_server_test.go
+++ b/libgo/go/crypto/tls/handshake_server_test.go
@@ -106,7 +106,6 @@ func TestClose(t *testing.T) {
}
}
-
func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) {
c, s := net.Pipe()
srv := Server(s, config)
diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go
index 8edbb11900c..a40d18fd9cd 100644
--- a/libgo/go/crypto/tls/key_agreement.go
+++ b/libgo/go/crypto/tls/key_agreement.go
@@ -32,11 +32,11 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
}
if len(ckx.ciphertext) < 2 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
if ciphertextLen != len(ckx.ciphertext)-2 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
ciphertext := ckx.ciphertext[2:]
@@ -54,7 +54,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
}
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
- return os.ErrorString("unexpected ServerKeyExchange")
+ return os.NewError("unexpected ServerKeyExchange")
}
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
@@ -78,7 +78,6 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello
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 {
@@ -146,7 +145,7 @@ Curve:
md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1)
if err != nil {
- return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String())
+ return nil, os.NewError("failed to sign ECDHE parameters: " + err.String())
}
skx := new(serverKeyExchangeMsg)
@@ -162,11 +161,11 @@ Curve:
func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
x, y := ka.curve.Unmarshal(ckx.ciphertext[1:])
if x == nil {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
@@ -176,12 +175,14 @@ func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *cl
return preMasterSecret, nil
}
+var errServerKeyExchange = os.NewError("invalid ServerKeyExchange")
+
func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
if len(skx.key) < 4 {
- goto Error
+ return errServerKeyExchange
}
if skx.key[0] != 3 { // named curve
- return os.ErrorString("server selected unsupported curve")
+ return os.NewError("server selected unsupported curve")
}
curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
@@ -193,39 +194,36 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH
case curveP521:
ka.curve = elliptic.P521()
default:
- return os.ErrorString("server selected unsupported curve")
+ return os.NewError("server selected unsupported curve")
}
publicLen := int(skx.key[3])
if publicLen+4 > len(skx.key) {
- goto Error
+ return errServerKeyExchange
}
ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen])
if ka.x == nil {
- goto Error
+ return errServerKeyExchange
}
serverECDHParams := skx.key[:4+publicLen]
sig := skx.key[4+publicLen:]
if len(sig) < 2 {
- goto Error
+ return errServerKeyExchange
}
sigLen := int(sig[0])<<8 | int(sig[1])
if sigLen+2 != len(sig) {
- goto Error
+ return errServerKeyExchange
}
sig = sig[2:]
md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig)
-
-Error:
- return os.ErrorString("invalid ServerKeyExchange")
}
func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
if ka.curve == nil {
- return nil, nil, os.ErrorString("missing ServerKeyExchange message")
+ return nil, nil, os.NewError("missing ServerKeyExchange message")
}
priv, mx, my, err := ka.curve.GenerateKey(config.rand())
if err != nil {
@@ -236,12 +234,12 @@ func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, client
xBytes := x.Bytes()
copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
- serialised := ka.curve.Marshal(mx, my)
+ serialized := 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)
+ ckx.ciphertext = make([]byte, 1+len(serialized))
+ ckx.ciphertext[0] = byte(len(serialized))
+ copy(ckx.ciphertext[1:], serialized)
return preMasterSecret, ckx, nil
}
diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go
index 7d0bb9f34b8..4f0859fee64 100644
--- a/libgo/go/crypto/tls/tls.go
+++ b/libgo/go/crypto/tls/tls.go
@@ -147,19 +147,19 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
}
if len(cert.Certificate) == 0 {
- err = os.ErrorString("crypto/tls: failed to parse certificate PEM data")
+ err = os.NewError("crypto/tls: failed to parse certificate PEM data")
return
}
keyDERBlock, _ := pem.Decode(keyPEMBlock)
if keyDERBlock == nil {
- err = os.ErrorString("crypto/tls: failed to parse key PEM data")
+ err = os.NewError("crypto/tls: failed to parse key PEM data")
return
}
key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
if err != nil {
- err = os.ErrorString("crypto/tls: failed to parse key")
+ err = os.NewError("crypto/tls: failed to parse key: " + err.String())
return
}
@@ -173,7 +173,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
}
if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 {
- err = os.ErrorString("crypto/tls: private key does not match public key")
+ err = os.NewError("crypto/tls: private key does not match public key")
return
}
diff --git a/libgo/go/crypto/twofish/twofish.go b/libgo/go/crypto/twofish/twofish.go
index 9303f03ffd8..2e537c60611 100644
--- a/libgo/go/crypto/twofish/twofish.go
+++ b/libgo/go/crypto/twofish/twofish.go
@@ -116,7 +116,7 @@ func (c *Cipher) Reset() {
c.k[i] = 0
}
for i := range c.s {
- for j := 0; j < 265; j++ {
+ for j := 0; j < 256; j++ {
c.s[i][j] = 0
}
}
@@ -269,7 +269,7 @@ func h(in, key []byte, offset int) uint32 {
// 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).
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) {
S1 := c.s[0]
S2 := c.s[1]
diff --git a/libgo/go/crypto/x509/cert_pool.go b/libgo/go/crypto/x509/cert_pool.go
index c295fd97e8d..16cd92efc3b 100644
--- a/libgo/go/crypto/x509/cert_pool.go
+++ b/libgo/go/crypto/x509/cert_pool.go
@@ -5,6 +5,7 @@
package x509
import (
+ "crypto/x509/pkix"
"encoding/pem"
"strings"
)
@@ -25,7 +26,7 @@ func NewCertPool() *CertPool {
}
}
-func nameToKey(name *Name) string {
+func nameToKey(name *pkix.Name) string {
return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
}
diff --git a/libgo/go/crypto/x509/pkix/pkix.go b/libgo/go/crypto/x509/pkix/pkix.go
new file mode 100644
index 00000000000..266fd557a52
--- /dev/null
+++ b/libgo/go/crypto/x509/pkix/pkix.go
@@ -0,0 +1,167 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkix contains shared, low level structures used for ASN.1 parsing
+// and serialization of X.509 certificates, CRL and OCSP.
+package pkix
+
+import (
+ "asn1"
+ "big"
+ "time"
+)
+
+// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.1.1.2.
+type AlgorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+ Parameters asn1.RawValue `asn1:"optional"`
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+type AttributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier
+ Value interface{}
+}
+
+// Extension represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.2.
+type Extension struct {
+ Id asn1.ObjectIdentifier
+ Critical bool `asn1:"optional"`
+ Value []byte
+}
+
+// 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}
+ oidLocality = []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, oidLocality)
+ 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
+}
+
+// CertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
+// signature.
+type CertificateList struct {
+ TBSCertList TBSCertificateList
+ SignatureAlgorithm AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+// HasExpired returns true iff currentTimeSeconds is past the expiry time of
+// certList.
+func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool {
+ return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds
+}
+
+// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type TBSCertificateList struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,default:2"`
+ Signature AlgorithmIdentifier
+ Issuer RDNSequence
+ ThisUpdate *time.Time
+ NextUpdate *time.Time
+ RevokedCertificates []RevokedCertificate `asn1:"optional"`
+ Extensions []Extension `asn1:"tag:0,optional,explicit"`
+}
+
+// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type RevokedCertificate struct {
+ SerialNumber *big.Int
+ RevocationTime *time.Time
+ Extensions []Extension `asn1:"optional"`
+}
diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go
index 9145880a237..4c0fecccbdf 100644
--- a/libgo/go/crypto/x509/verify.go
+++ b/libgo/go/crypto/x509/verify.go
@@ -62,7 +62,6 @@ func (h HostnameError) String() string {
return "certificate is valid for " + valid + ", not " + h.Host
}
-
// UnknownAuthorityError results when the certificate issuer is unknown
type UnknownAuthorityError struct {
cert *Certificate
@@ -171,8 +170,14 @@ func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain [
chains = append(chains, appendToFreshChain(currentChain, root))
}
+nextIntermediate:
for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) {
intermediate := opts.Intermediates.certs[intermediateNum]
+ for _, cert := range currentChain {
+ if cert == intermediate {
+ continue nextIntermediate
+ }
+ }
err = intermediate.isValid(intermediateCertificate, opts)
if err != nil {
continue
@@ -202,8 +207,8 @@ func matchHostnames(pattern, host string) bool {
return false
}
- patternParts := strings.Split(pattern, ".", -1)
- hostParts := strings.Split(host, ".", -1)
+ patternParts := strings.Split(pattern, ".")
+ hostParts := strings.Split(host, ".")
if len(patternParts) != len(hostParts) {
return false
diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go
index 6a103dcfba7..111f60eb114 100644
--- a/libgo/go/crypto/x509/verify_test.go
+++ b/libgo/go/crypto/x509/verify_test.go
@@ -72,23 +72,24 @@ var verifyTests = []verifyTest{
},
},
{
- leaf: googleLeaf,
- intermediates: []string{verisignRoot, thawteIntermediate},
- roots: []string{verisignRoot},
+ leaf: dnssecExpLeaf,
+ intermediates: []string{startComIntermediate},
+ roots: []string{startComRoot},
currentTime: 1302726541,
expectedChains: [][]string{
- []string{"Google", "Thawte", "VeriSign"},
+ []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
},
},
{
leaf: dnssecExpLeaf,
- intermediates: []string{startComIntermediate},
+ intermediates: []string{startComIntermediate, startComRoot},
roots: []string{startComRoot},
currentTime: 1302726541,
expectedChains: [][]string{
[]string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
},
},
}
@@ -120,7 +121,7 @@ func expectAuthorityUnknown(t *testing.T, i int, err os.Error) (ok bool) {
func certificateFromPEM(pemBytes string) (*Certificate, os.Error) {
block, _ := pem.Decode([]byte(pemBytes))
if block == nil {
- return nil, os.ErrorString("failed to decode PEM")
+ return nil, os.NewError("failed to decode PEM")
}
return ParseCertificate(block.Bytes)
}
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
index d0c5a26a9a8..8fda4715927 100644
--- a/libgo/go/crypto/x509/x509.go
+++ b/libgo/go/crypto/x509/x509.go
@@ -9,11 +9,12 @@ import (
"asn1"
"big"
"bytes"
- "container/vector"
"crypto"
+ "crypto/dsa"
"crypto/rsa"
"crypto/sha1"
- "hash"
+ "crypto/x509/pkix"
+ "encoding/pem"
"io"
"os"
"time"
@@ -22,30 +23,25 @@ import (
// pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key.
type pkcs1PrivateKey struct {
Version int
- N asn1.RawValue
+ N *big.Int
E int
- D asn1.RawValue
- P asn1.RawValue
- Q asn1.RawValue
+ D *big.Int
+ P *big.Int
+ Q *big.Int
// We ignore these values, if present, because rsa will calculate them.
- Dp asn1.RawValue "optional"
- Dq asn1.RawValue "optional"
- Qinv asn1.RawValue "optional"
+ Dp *big.Int `asn1:"optional"`
+ Dq *big.Int `asn1:"optional"`
+ Qinv *big.Int `asn1:"optional"`
- AdditionalPrimes []pkcs1AddtionalRSAPrime "optional"
+ AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"`
}
-type pkcs1AddtionalRSAPrime struct {
- Prime asn1.RawValue
+type pkcs1AdditionalRSAPrime struct {
+ Prime *big.Int
// We ignore these values because rsa will calculate them.
- Exp asn1.RawValue
- Coeff 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
+ Exp *big.Int
+ Coeff *big.Int
}
// ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
@@ -61,32 +57,28 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
}
if priv.Version > 1 {
- return nil, os.ErrorString("x509: unsupported private key version")
+ return nil, os.NewError("x509: unsupported private key version")
}
- if !rawValueIsInteger(&priv.N) ||
- !rawValueIsInteger(&priv.D) ||
- !rawValueIsInteger(&priv.P) ||
- !rawValueIsInteger(&priv.Q) {
- err = asn1.StructuralError{"tags don't match"}
- return
+ if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
+ return nil, os.NewError("private key contains zero or negative value")
}
key = new(rsa.PrivateKey)
key.PublicKey = rsa.PublicKey{
E: priv.E,
- N: new(big.Int).SetBytes(priv.N.Bytes),
+ N: priv.N,
}
- key.D = new(big.Int).SetBytes(priv.D.Bytes)
+ key.D = priv.D
key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
- key.Primes[0] = new(big.Int).SetBytes(priv.P.Bytes)
- key.Primes[1] = new(big.Int).SetBytes(priv.Q.Bytes)
+ key.Primes[0] = priv.P
+ key.Primes[1] = priv.Q
for i, a := range priv.AdditionalPrimes {
- if !rawValueIsInteger(&a.Prime) {
- return nil, asn1.StructuralError{"tags don't match"}
+ if a.Prime.Sign() <= 0 {
+ return nil, os.NewError("private key contains zero or negative prime")
}
- key.Primes[i+2] = new(big.Int).SetBytes(a.Prime.Bytes)
+ key.Primes[i+2] = a.Prime
// We ignore the other two values because rsa will calculate
// them as needed.
}
@@ -100,19 +92,6 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
return
}
-// rawValueForBig returns an asn1.RawValue which represents the given integer.
-func rawValueForBig(n *big.Int) asn1.RawValue {
- b := n.Bytes()
- if n.Sign() >= 0 && len(b) > 0 && b[0]&0x80 != 0 {
- // This positive number would be interpreted as a negative
- // number in ASN.1 because the MSB is set.
- padded := make([]byte, len(b)+1)
- copy(padded[1:], b)
- b = padded
- }
- return asn1.RawValue{Tag: 2, Bytes: b}
-}
-
// MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
key.Precompute()
@@ -124,21 +103,21 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
priv := pkcs1PrivateKey{
Version: version,
- N: rawValueForBig(key.N),
+ N: key.N,
E: key.PublicKey.E,
- D: rawValueForBig(key.D),
- P: rawValueForBig(key.Primes[0]),
- Q: rawValueForBig(key.Primes[1]),
- Dp: rawValueForBig(key.Precomputed.Dp),
- Dq: rawValueForBig(key.Precomputed.Dq),
- Qinv: rawValueForBig(key.Precomputed.Qinv),
+ D: key.D,
+ P: key.Primes[0],
+ Q: key.Primes[1],
+ Dp: key.Precomputed.Dp,
+ Dq: key.Precomputed.Dq,
+ Qinv: key.Precomputed.Qinv,
}
- priv.AdditionalPrimes = make([]pkcs1AddtionalRSAPrime, len(key.Precomputed.CRTValues))
+ priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
for i, values := range key.Precomputed.CRTValues {
- priv.AdditionalPrimes[i].Prime = rawValueForBig(key.Primes[2+i])
- priv.AdditionalPrimes[i].Exp = rawValueForBig(values.Exp)
- priv.AdditionalPrimes[i].Coeff = rawValueForBig(values.Coeff)
+ priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
+ priv.AdditionalPrimes[i].Exp = values.Exp
+ priv.AdditionalPrimes[i].Coeff = values.Coeff
}
b, _ := asn1.Marshal(priv)
@@ -150,35 +129,30 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
type certificate struct {
Raw asn1.RawContent
TBSCertificate tbsCertificate
- SignatureAlgorithm algorithmIdentifier
+ SignatureAlgorithm pkix.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
+ Version int `asn1:"optional,explicit,default:1,tag:0"`
+ SerialNumber *big.Int
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ Issuer pkix.RDNSequence
Validity validity
- Subject rdnSequence
+ Subject pkix.RDNSequence
PublicKey publicKeyInfo
- UniqueId asn1.BitString "optional,tag:1"
- SubjectUniqueId asn1.BitString "optional,tag:2"
- Extensions []extension "optional,explicit,tag:3"
+ UniqueId asn1.BitString `asn1:"optional,tag:1"`
+ SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
+ Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}
-type algorithmIdentifier struct {
- Algorithm asn1.ObjectIdentifier
+type dsaAlgorithmParameters struct {
+ P, Q, G *big.Int
}
-type rdnSequence []relativeDistinguishedNameSET
-
-type relativeDistinguishedNameSET []attributeTypeAndValue
-
-type attributeTypeAndValue struct {
- Type asn1.ObjectIdentifier
- Value interface{}
+type dsaSignature struct {
+ R, S *big.Int
}
type validity struct {
@@ -187,19 +161,13 @@ type validity struct {
type publicKeyInfo struct {
Raw asn1.RawContent
- Algorithm algorithmIdentifier
+ Algorithm pkix.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"
+ Id []byte `asn1:"optional,tag:0"`
}
type SignatureAlgorithm int
@@ -212,6 +180,8 @@ const (
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
+ DSAWithSHA1
+ DSAWithSHA256
)
type PublicKeyAlgorithm int
@@ -219,133 +189,96 @@ type PublicKeyAlgorithm int
const (
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
RSA
+ DSA
)
-// 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)
- }
- }
- }
-}
-
+// OIDs for signature algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+//
+//
+// RFC 3279 2.2.1 RSA Signature Algorithms
+//
+// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
+//
+// md5WithRSAEncryption OBJECT IDENTIFER ::= { pkcs-1 4 }
+//
+// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
+//
+// dsaWithSha1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
+//
+//
+// RFC 4055 5 PKCS #1 Version 1.5
+//
+// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
+//
+// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
+//
+// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
+//
+//
+// RFC 5758 3.1 DSA Signature Algorithms
+//
+// dsaWithSha356 OBJECT IDENTIFER ::= {
+// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+// algorithms(4) id-dsa-with-sha2(3) 2}
+//
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}
+ oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
+ oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
+ oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
+ oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
+ oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
+ oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+ oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
+ oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2}
)
-// 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
- }
+func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
+ switch {
+ case oid.Equal(oidSignatureMD2WithRSA):
+ return MD2WithRSA
+ case oid.Equal(oidSignatureMD5WithRSA):
+ return MD5WithRSA
+ case oid.Equal(oidSignatureSHA1WithRSA):
+ return SHA1WithRSA
+ case oid.Equal(oidSignatureSHA256WithRSA):
+ return SHA256WithRSA
+ case oid.Equal(oidSignatureSHA384WithRSA):
+ return SHA384WithRSA
+ case oid.Equal(oidSignatureSHA512WithRSA):
+ return SHA512WithRSA
+ case oid.Equal(oidSignatureDSAWithSHA1):
+ return DSAWithSHA1
+ case oid.Equal(oidSignatureDSAWithSHA256):
+ return DSAWithSHA256
}
-
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
- }
- }
+// RFC 3279, 2.3 Public Key Algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+// rsadsi(113549) pkcs(1) 1 }
+//
+// rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 }
+//
+// id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+// x9-57(10040) x9cm(4) 1 }
+var (
+ oidPublicKeyRsa = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
+ oidPublicKeyDsa = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
+)
+func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
+ switch {
+ case oid.Equal(oidPublicKeyRsa):
+ return RSA
+ case oid.Equal(oidPublicKeyDsa):
+ return DSA
+ }
return UnknownPublicKeyAlgorithm
}
@@ -414,9 +347,9 @@ type Certificate struct {
PublicKey interface{}
Version int
- SerialNumber []byte
- Issuer Name
- Subject Name
+ SerialNumber *big.Int
+ Issuer pkix.Name
+ Subject pkix.Name
NotBefore, NotAfter *time.Time // Validity bounds.
KeyUsage KeyUsage
@@ -485,26 +418,58 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) {
// TODO(agl): don't ignore the path length constraint.
- var h hash.Hash
+ return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature)
+}
+
+// CheckSignature verifies that signature is a valid signature over signed from
+// c's public key.
+func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err os.Error) {
var hashType crypto.Hash
- switch c.SignatureAlgorithm {
- case SHA1WithRSA:
- h = sha1.New()
+ switch algo {
+ case SHA1WithRSA, DSAWithSHA1:
hashType = crypto.SHA1
+ case SHA256WithRSA, DSAWithSHA256:
+ hashType = crypto.SHA256
+ case SHA384WithRSA:
+ hashType = crypto.SHA384
+ case SHA512WithRSA:
+ hashType = crypto.SHA512
default:
return UnsupportedAlgorithmError{}
}
- pub, ok := parent.PublicKey.(*rsa.PublicKey)
- if !ok {
+ h := hashType.New()
+ if h == nil {
return UnsupportedAlgorithmError{}
}
- h.Write(c.RawTBSCertificate)
+ h.Write(signed)
digest := h.Sum()
- return rsa.VerifyPKCS1v15(pub, hashType, digest, c.Signature)
+ switch pub := c.PublicKey.(type) {
+ case *rsa.PublicKey:
+ return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
+ case *dsa.PublicKey:
+ dsaSig := new(dsaSignature)
+ if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
+ return err
+ }
+ if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
+ return os.NewError("DSA signature contained zero or negative values")
+ }
+ if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
+ return os.NewError("DSA verification failure")
+ }
+ return
+ }
+ return UnsupportedAlgorithmError{}
+}
+
+// CheckCRLSignature checks that the signature in crl is from c.
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err os.Error) {
+ algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)
+ return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
}
type UnhandledCriticalExtension struct{}
@@ -514,12 +479,12 @@ func (h UnhandledCriticalExtension) String() string {
}
type basicConstraints struct {
- IsCA bool "optional"
- MaxPathLen int "optional"
+ IsCA bool `asn1:"optional"`
+ MaxPathLen int `asn1:"optional"`
}
type rsaPublicKey struct {
- N asn1.RawValue
+ N *big.Int
E int
}
@@ -531,17 +496,18 @@ type policyInformation struct {
// RFC 5280, 4.2.1.10
type nameConstraints struct {
- Permitted []generalSubtree "optional,tag:0"
- Excluded []generalSubtree "optional,tag:1"
+ Permitted []generalSubtree `asn1:"optional,tag:0"`
+ Excluded []generalSubtree `asn1:"optional,tag:1"`
}
type generalSubtree struct {
- Name string "tag:2,optional,ia5"
- Min int "optional,tag:0"
- Max int "optional,tag:1"
+ Name string `asn1:"tag:2,optional,ia5"`
+ Min int `asn1:"optional,tag:0"`
+ Max int `asn1:"optional,tag:1"`
}
-func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
+func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, os.Error) {
+ asn1Data := keyData.PublicKey.RightAlign()
switch algo {
case RSA:
p := new(rsaPublicKey)
@@ -550,19 +516,38 @@ func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.E
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),
+ N: p.N,
+ }
+ return pub, nil
+ case DSA:
+ var p *big.Int
+ _, err := asn1.Unmarshal(asn1Data, &p)
+ if err != nil {
+ return nil, err
+ }
+ paramsData := keyData.Algorithm.Parameters.FullBytes
+ params := new(dsaAlgorithmParameters)
+ _, err = asn1.Unmarshal(paramsData, params)
+ if err != nil {
+ return nil, err
+ }
+ if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
+ return nil, os.NewError("zero or negative DSA parameter")
+ }
+ pub := &dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: params.P,
+ Q: params.Q,
+ G: params.G,
+ },
+ Y: p,
}
return pub, nil
default:
return nil, nil
}
-
panic("unreachable")
}
@@ -579,15 +564,19 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
out.PublicKeyAlgorithm =
getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
var err os.Error
- out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, in.TBSCertificate.PublicKey.PublicKey.RightAlign())
+ out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey)
if err != nil {
return nil, err
}
+ if in.TBSCertificate.SerialNumber.Sign() < 0 {
+ return nil, os.NewError("negative serial number")
+ }
+
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.SerialNumber = in.TBSCertificate.SerialNumber
+ out.Issuer.FillFromRDNSequence(&in.TBSCertificate.Issuer)
+ out.Subject.FillFromRDNSequence(&in.TBSCertificate.Subject)
out.NotBefore = in.TBSCertificate.Validity.NotBefore
out.NotAfter = in.TBSCertificate.Validity.NotAfter
@@ -611,13 +600,13 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
}
case 19:
// RFC 5280, 4.2.1.9
- var constriants basicConstraints
- _, err := asn1.Unmarshal(e.Value, &constriants)
+ var constraints basicConstraints
+ _, err := asn1.Unmarshal(e.Value, &constraints)
if err == nil {
out.BasicConstraintsValid = true
- out.IsCA = constriants.IsCA
- out.MaxPathLen = constriants.MaxPathLen
+ out.IsCA = constraints.IsCA
+ out.MaxPathLen = constraints.MaxPathLen
continue
}
case 17:
@@ -804,7 +793,7 @@ func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) {
// 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)
+ var v []*certificate
for len(asn1Data) > 0 {
cert := new(certificate)
@@ -813,12 +802,12 @@ func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
if err != nil {
return nil, err
}
- v.Push(cert)
+ v = append(v, cert)
}
- ret := make([]*Certificate, v.Len())
- for i := 0; i < v.Len(); i++ {
- cert, err := parseCertificate(v.At(i).(*certificate))
+ ret := make([]*Certificate, len(v))
+ for i, ci := range v {
+ cert, err := parseCertificate(ci)
if err != nil {
return nil, err
}
@@ -845,8 +834,8 @@ var (
oidExtensionNameConstraints = []int{2, 5, 29, 30}
)
-func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
- ret = make([]extension, 7 /* maximum number of elements. */ )
+func buildExtensions(template *Certificate) (ret []pkix.Extension, err os.Error) {
+ ret = make([]pkix.Extension, 7 /* maximum number of elements. */ )
n := 0
if template.KeyUsage != 0 {
@@ -963,7 +952,7 @@ var (
// 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()},
+ N: pub.N,
E: pub.E,
})
if err != nil {
@@ -982,12 +971,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
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(),
+ SerialNumber: template.SerialNumber,
+ SignatureAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
+ Issuer: parent.Subject.ToRDNSequence(),
Validity: validity{template.NotBefore, template.NotAfter},
- Subject: template.Subject.toRDNSequence(),
- PublicKey: publicKeyInfo{nil, algorithmIdentifier{oidRSA}, encodedPublicKey},
+ Subject: template.Subject.ToRDNSequence(),
+ PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey},
Extensions: extensions,
}
@@ -1010,8 +999,75 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
cert, err = asn1.Marshal(certificate{
nil,
c,
- algorithmIdentifier{oidSHA1WithRSA},
+ pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA},
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
return
}
+
+// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
+// CRL.
+var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
+// pemType is the type of a PEM encoded CRL.
+var pemType = "X509 CRL"
+
+// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
+// encoded CRLs will appear where they should be DER encoded, so this function
+// will transparently handle PEM encoding as long as there isn't any leading
+// garbage.
+func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+ if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
+ block, _ := pem.Decode(crlBytes)
+ if block != nil && block.Type == pemType {
+ crlBytes = block.Bytes
+ }
+ }
+ return ParseDERCRL(crlBytes)
+}
+
+// ParseDERCRL parses a DER encoded CRL from the given bytes.
+func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err os.Error) {
+ certList = new(pkix.CertificateList)
+ _, err = asn1.Unmarshal(derBytes, certList)
+ if err != nil {
+ certList = nil
+ }
+ return
+}
+
+// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
+// contains the given list of revoked certificates.
+func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err os.Error) {
+ tbsCertList := pkix.TBSCertificateList{
+ Version: 2,
+ Signature: pkix.AlgorithmIdentifier{
+ Algorithm: oidSignatureSHA1WithRSA,
+ },
+ Issuer: c.Subject.ToRDNSequence(),
+ ThisUpdate: now,
+ NextUpdate: expiry,
+ RevokedCertificates: revokedCerts,
+ }
+
+ tbsCertListContents, err := asn1.Marshal(tbsCertList)
+ if err != nil {
+ return
+ }
+
+ h := sha1.New()
+ h.Write(tbsCertListContents)
+ digest := h.Sum()
+
+ signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest)
+ if err != nil {
+ return
+ }
+
+ return asn1.Marshal(pkix.CertificateList{
+ TBSCertList: tbsCertList,
+ SignatureAlgorithm: pkix.AlgorithmIdentifier{
+ Algorithm: oidSignatureSHA1WithRSA,
+ },
+ SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+}
diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go
index a42113addda..dc216505efe 100644
--- a/libgo/go/crypto/x509/x509_test.go
+++ b/libgo/go/crypto/x509/x509_test.go
@@ -7,8 +7,11 @@ package x509
import (
"asn1"
"big"
+ "crypto/dsa"
"crypto/rand"
"crypto/rsa"
+ "crypto/x509/pkix"
+ "encoding/base64"
"encoding/hex"
"encoding/pem"
"testing"
@@ -54,6 +57,12 @@ func fromBase10(base10 string) *big.Int {
return i
}
+func bigFromHexString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 16)
+ return ret
+}
+
var rsaPrivateKey = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
@@ -200,8 +209,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
}
template := Certificate{
- SerialNumber: []byte{1},
- Subject: Name{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
CommonName: "test.example.com",
Organization: []string{"Acme Co"},
},
@@ -245,3 +254,178 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
return
}
}
+
+// Self-signed certificate using DSA with SHA1
+var dsaCertPem = `-----BEGIN CERTIFICATE-----
+MIIEDTCCA82gAwIBAgIJALHPghaoxeDhMAkGByqGSM44BAMweTELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAk5DMQ8wDQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2ds
+ZSwgSW5jMRIwEAYDVQQDEwlKb24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFs
+bGllQGdvb2dsZS5jb20wHhcNMTEwNTE0MDMwMTQ1WhcNMTEwNjEzMDMwMTQ1WjB5
+MQswCQYDVQQGEwJVUzELMAkGA1UECBMCTkMxDzANBgNVBAcTBk5ld3RvbjEUMBIG
+A1UEChMLR29vZ2xlLCBJbmMxEjAQBgNVBAMTCUpvbiBBbGxpZTEiMCAGCSqGSIb3
+DQEJARYTam9uYWxsaWVAZ29vZ2xlLmNvbTCCAbcwggEsBgcqhkjOOAQBMIIBHwKB
+gQC8hLUnQ7FpFYu4WXTj6DKvXvz8QrJkNJCVMTpKAT7uBpobk32S5RrPKXocd4gN
+8lyGB9ggS03EVlEwXvSmO0DH2MQtke2jl9j1HLydClMf4sbx5V6TV9IFw505U1iW
+jL7awRMgxge+FsudtJK254FjMFo03ZnOQ8ZJJ9E6AEDrlwIVAJpnBn9moyP11Ox5
+Asc/5dnjb6dPAoGBAJFHd4KVv1iTVCvEG6gGiYop5DJh28hUQcN9kul+2A0yPUSC
+X93oN00P8Vh3eYgSaCWZsha7zDG53MrVJ0Zf6v/X/CoZNhLldeNOepivTRAzn+Rz
+kKUYy5l1sxYLHQKF0UGNCXfFKZT0PCmgU+PWhYNBBMn6/cIh44vp85ideo5CA4GE
+AAKBgFmifCafzeRaohYKXJgMGSEaggCVCRq5xdyDCat+wbOkjC4mfG01/um3G8u5
+LxasjlWRKTR/tcAL7t0QuokVyQaYdVypZXNaMtx1db7YBuHjj3aP+8JOQRI9xz8c
+bp5NDJ5pISiFOv4p3GZfqZPcqckDt78AtkQrmnal2txhhjF6o4HeMIHbMB0GA1Ud
+DgQWBBQVyyr7hO11ZFFpWX50298Sa3V+rzCBqwYDVR0jBIGjMIGggBQVyyr7hO11
+ZFFpWX50298Sa3V+r6F9pHsweTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5DMQ8w
+DQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2dsZSwgSW5jMRIwEAYDVQQDEwlK
+b24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFsbGllQGdvb2dsZS5jb22CCQCx
+z4IWqMXg4TAMBgNVHRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUPtn/5j8Q1jJI
+7ggOIsgrhgUdjGQCFCsmDq1H11q9+9Wp9IMeGrTSKHIM
+-----END CERTIFICATE-----
+`
+
+func TestParseCertificateWithDsaPublicKey(t *testing.T) {
+ expectedKey := &dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: bigFromHexString("00BC84B52743B169158BB85974E3E832AF5EFCFC42B264349095313A4A013EEE069A1B937D92E51ACF297A1C77880DF25C8607D8204B4DC45651305EF4A63B40C7D8C42D91EDA397D8F51CBC9D0A531FE2C6F1E55E9357D205C39D395358968CBEDAC11320C607BE16CB9DB492B6E78163305A34DD99CE43C64927D13A0040EB97"),
+ Q: bigFromHexString("009A67067F66A323F5D4EC7902C73FE5D9E36FA74F"),
+ G: bigFromHexString("009147778295BF5893542BC41BA806898A29E43261DBC85441C37D92E97ED80D323D44825FDDE8374D0FF15877798812682599B216BBCC31B9DCCAD527465FEAFFD7FC2A193612E575E34E7A98AF4D10339FE47390A518CB9975B3160B1D0285D1418D0977C52994F43C29A053E3D685834104C9FAFDC221E38BE9F3989D7A8E42"),
+ },
+ Y: bigFromHexString("59A27C269FCDE45AA2160A5C980C19211A820095091AB9C5DC8309AB7EC1B3A48C2E267C6D35FEE9B71BCBB92F16AC8E559129347FB5C00BEEDD10BA8915C90698755CA965735A32DC7575BED806E1E38F768FFBC24E41123DC73F1C6E9E4D0C9E692128853AFE29DC665FA993DCA9C903B7BF00B6442B9A76A5DADC6186317A"),
+ }
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ if cert.PublicKeyAlgorithm != DSA {
+ t.Errorf("Parsed key algorithm was not DSA")
+ }
+ parsedKey, ok := cert.PublicKey.(*dsa.PublicKey)
+ if !ok {
+ t.Fatalf("Parsed key was not a DSA key: %s", err)
+ }
+ if expectedKey.Y.Cmp(parsedKey.Y) != 0 ||
+ expectedKey.P.Cmp(parsedKey.P) != 0 ||
+ expectedKey.Q.Cmp(parsedKey.Q) != 0 ||
+ expectedKey.G.Cmp(parsedKey.G) != 0 {
+ t.Fatal("Parsed key differs from expected key")
+ }
+}
+
+func TestParseCertificateWithDSASignatureAlgorithm(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ if cert.SignatureAlgorithm != DSAWithSHA1 {
+ t.Errorf("Parsed signature algorithm was not DSAWithSHA1")
+ }
+}
+
+func TestVerifyCertificateWithDSASignature(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ // test cert is self-signed
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Fatalf("DSA Certificate verfication failed: %s", err)
+ }
+}
+
+const pemCertificate = `-----BEGIN CERTIFICATE-----
+MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE
+AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO
+BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED
+SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo
+fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB
+/zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs
+ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4
+YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui
+0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k=
+-----END CERTIFICATE-----`
+
+func TestCRLCreation(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, _ := ParsePKCS1PrivateKey(block.Bytes)
+ block, _ = pem.Decode([]byte(pemCertificate))
+ cert, _ := ParseCertificate(block.Bytes)
+
+ now := time.SecondsToUTC(1000)
+ expiry := time.SecondsToUTC(10000)
+
+ revokedCerts := []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(1),
+ RevocationTime: now,
+ },
+ {
+ SerialNumber: big.NewInt(42),
+ RevocationTime: now,
+ },
+ }
+
+ crlBytes, err := cert.CreateCRL(rand.Reader, priv, revokedCerts, now, expiry)
+ if err != nil {
+ t.Errorf("error creating CRL: %s", err)
+ }
+
+ _, err = ParseDERCRL(crlBytes)
+ if err != nil {
+ t.Errorf("error reparsing CRL: %s", err)
+ }
+}
+
+func fromBase64(in string) []byte {
+ out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ _, err := base64.StdEncoding.Decode(out, []byte(in))
+ if err != nil {
+ panic("failed to base64 decode")
+ }
+ return out
+}
+
+func TestParseDERCRL(t *testing.T) {
+ derBytes := fromBase64(derCRLBase64)
+ certList, err := ParseDERCRL(derBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 88
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(1302517272) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+func TestParsePEMCRL(t *testing.T) {
+ pemBytes := fromBase64(pemCRLBase64)
+ certList, err := ParseCRL(pemBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 2
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(1302517272) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
+
+const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
diff --git a/libgo/go/crypto/xtea/block.go b/libgo/go/crypto/xtea/block.go
index 3ac36d038f8..bf5d245992d 100644
--- a/libgo/go/crypto/xtea/block.go
+++ b/libgo/go/crypto/xtea/block.go
@@ -22,7 +22,7 @@ func blockToUint32(src []byte) (uint32, uint32) {
return r0, r1
}
-// uint32ToBlock writes two unint32s into an 8 byte data block.
+// uint32ToBlock writes two uint32s into an 8 byte data block.
// Values are written as big endian.
func uint32ToBlock(v0, v1 uint32, dst []byte) {
dst[0] = byte(v0 >> 24)
diff --git a/libgo/go/crypto/xtea/cipher.go b/libgo/go/crypto/xtea/cipher.go
index f2a5da0035c..b3fba3c8418 100644
--- a/libgo/go/crypto/xtea/cipher.go
+++ b/libgo/go/crypto/xtea/cipher.go
@@ -48,13 +48,13 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
// BlockSize returns the XTEA block size, 8 bytes.
// It is necessary to satisfy the Cipher interface in the
-// package "crypto/block".
+// package "crypto/cipher".
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).
+// instead, use an encryption mode like CBC (see crypto/cipher/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.
diff --git a/libgo/go/crypto/xtea/xtea_test.go b/libgo/go/crypto/xtea/xtea_test.go
index 03934f1695e..217d96adc20 100644
--- a/libgo/go/crypto/xtea/xtea_test.go
+++ b/libgo/go/crypto/xtea/xtea_test.go
@@ -8,7 +8,7 @@ import (
"testing"
)
-// A sample test key for when we just want to initialise a cipher
+// A sample test key for when we just want to initialize 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
@@ -26,12 +26,12 @@ func TestBlocksize(t *testing.T) {
result := c.BlockSize()
if result != 8 {
- t.Errorf("BlockSize function - expected 8, gotr %d", result)
+ t.Errorf("BlockSize function - expected 8, got %d", result)
return
}
}
-// A series of test values to confirm that the Cipher.table array was initialised correctly
+// A series of test values to confirm that the Cipher.table array was initialized correctly
var testTable = []uint32{
0x00112233, 0x6B1568B8, 0xE28CE030, 0xC5089E2D, 0xC5089E2D, 0x1EFBD3A2, 0xA7845C2A, 0x78EF0917,
0x78EF0917, 0x172682D0, 0x5B6AC714, 0x822AC955, 0x3DE68511, 0xDC1DFECA, 0x2062430E, 0x3611343F,
@@ -43,7 +43,7 @@ var testTable = []uint32{
0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB,
}
-// Test that the cipher context is initialised correctly
+// Test that the cipher context is initialized correctly
func TestCipherInit(t *testing.T) {
c, err := NewCipher(testKey)
if err != nil {
@@ -53,7 +53,7 @@ func TestCipherInit(t *testing.T) {
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])
+ t.Errorf("NewCipher() failed to initialize Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
break
}
}
diff --git a/libgo/go/csv/reader.go b/libgo/go/csv/reader.go
new file mode 100644
index 00000000000..ea2c266a47d
--- /dev/null
+++ b/libgo/go/csv/reader.go
@@ -0,0 +1,372 @@
+// 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 csv reads and writes comma-separated values (CSV) files.
+//
+// A csv file contains zero or more records of one or more fields per record.
+// Each record is separated by the newline character. The final record may
+// optionally be followed by a newline character.
+//
+// field1,field2,field3
+//
+// White space is considered part of a field.
+//
+// Carriage returns before newline characters are silently removed.
+//
+// Blank lines are ignored. A line with only whitespace characters (excluding
+// the ending newline character) is not considered a blank line.
+//
+// Fields which start and stop with the quote character " are called
+// quoted-fields. The beginning and ending quote are not part of the
+// field.
+//
+// The source:
+//
+// normal string,"quoted-field"
+//
+// results in the fields
+//
+// {`normal string`, `quoted-field`}
+//
+// Within a quoted-field a quote character followed by a second quote
+// character is considered a single quote.
+//
+// "the ""word"" is true","a ""quoted-field"""
+//
+// results in
+//
+// {`the "word" is true`, `a "quoted-field"`}
+//
+// Newlines and commas may be included in a quoted-field
+//
+// "Multi-line
+// field","comma is ,"
+//
+// results in
+//
+// {`Multi-line
+// field`, `comma is ,`}
+package csv
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "unicode"
+)
+
+// A ParseError is returned for parsing errors.
+// The first line is 1. The first column is 0.
+type ParseError struct {
+ Line int // Line where the error occurred
+ Column int // Column (rune index) where the error occurred
+ Error os.Error // The actual error
+}
+
+func (e *ParseError) String() string {
+ return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Error)
+}
+
+// These are the errors that can be returned in ParseError.Error
+var (
+ ErrTrailingComma = os.NewError("extra delimiter at end of line")
+ ErrBareQuote = os.NewError("bare \" in non-quoted-field")
+ ErrQuote = os.NewError("extraneous \" in field")
+ ErrFieldCount = os.NewError("wrong number of fields in line")
+)
+
+// A Reader reads records from a CSV-encoded file.
+//
+// As returned by NewReader, a Reader expects input conforming to RFC 4180.
+// The exported fields can be changed to customize the details before the
+// first call to Read or ReadAll.
+//
+// Comma is the field delimiter. It defaults to ','.
+//
+// Comment, if not 0, is the comment character. Lines beginning with the
+// Comment character are ignored.
+//
+// If FieldsPerRecord is positive, Read requires each record to
+// have the given number of fields. If FieldsPerRecord is 0, Read sets it to
+// the number of fields in the first record, so that future records must
+// have the same field count.
+//
+// If LazyQuotes is true, a quote may appear in an unquoted field and a
+// non-doubled quote may appear in a quoted field.
+//
+// If TrailingComma is true, the last field may be an unquoted empty field.
+//
+// If TrimLeadingSpace is true, leading white space in a field is ignored.
+type Reader struct {
+ Comma int // Field delimiter (set to ',' by NewReader)
+ Comment int // Comment character for start of line
+ FieldsPerRecord int // Number of expected fields per record
+ LazyQuotes bool // Allow lazy quotes
+ TrailingComma bool // Allow trailing comma
+ TrimLeadingSpace bool // Trim leading space
+ line int
+ column int
+ r *bufio.Reader
+ field bytes.Buffer
+}
+
+// NewReader returns a new Reader that reads from r.
+func NewReader(r io.Reader) *Reader {
+ return &Reader{
+ Comma: ',',
+ r: bufio.NewReader(r),
+ }
+}
+
+// error creates a new ParseError based on err.
+func (r *Reader) error(err os.Error) os.Error {
+ return &ParseError{
+ Line: r.line,
+ Column: r.column,
+ Error: err,
+ }
+}
+
+// Read reads one record from r. The record is a slice of strings with each
+// string representing one field.
+func (r *Reader) Read() (record []string, err os.Error) {
+ for {
+ record, err = r.parseRecord()
+ if record != nil {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if r.FieldsPerRecord > 0 {
+ if len(record) != r.FieldsPerRecord {
+ r.column = 0 // report at start of record
+ return record, r.error(ErrFieldCount)
+ }
+ } else if r.FieldsPerRecord == 0 {
+ r.FieldsPerRecord = len(record)
+ }
+ return record, nil
+}
+
+// ReadAll reads all the remaining records from r.
+// Each record is a slice of fields.
+func (r *Reader) ReadAll() (records [][]string, err os.Error) {
+ for {
+ record, err := r.Read()
+ if err == os.EOF {
+ return records, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ records = append(records, record)
+ }
+ panic("unreachable")
+}
+
+// readRune reads one rune from r, folding \r\n to \n and keeping track
+// of how far into the line we have read. r.column will point to the start
+// of this rune, not the end of this rune.
+func (r *Reader) readRune() (int, os.Error) {
+ rune, _, err := r.r.ReadRune()
+
+ // Handle \r\n here. We make the simplifying assumption that
+ // anytime \r is followed by \n that it can be folded to \n.
+ // We will not detect files which contain both \r\n and bare \n.
+ if rune == '\r' {
+ rune, _, err = r.r.ReadRune()
+ if err == nil {
+ if rune != '\n' {
+ r.r.UnreadRune()
+ rune = '\r'
+ }
+ }
+ }
+ r.column++
+ return rune, err
+}
+
+// unreadRune puts the last rune read from r back.
+func (r *Reader) unreadRune() {
+ r.r.UnreadRune()
+ r.column--
+}
+
+// skip reads runes up to and including the rune delim or until error.
+func (r *Reader) skip(delim int) os.Error {
+ for {
+ rune, err := r.readRune()
+ if err != nil {
+ return err
+ }
+ if rune == delim {
+ return nil
+ }
+ }
+ panic("unreachable")
+}
+
+// parseRecord reads and parses a single csv record from r.
+func (r *Reader) parseRecord() (fields []string, err os.Error) {
+ // Each record starts on a new line. We increment our line
+ // number (lines start at 1, not 0) and set column to -1
+ // so as we increment in readRune it points to the character we read.
+ r.line++
+ r.column = -1
+
+ // Peek at the first rune. If it is an error we are done.
+ // If we are support comments and it is the comment character
+ // then skip to the end of line.
+
+ rune, _, err := r.r.ReadRune()
+ if err != nil {
+ return nil, err
+ }
+
+ if r.Comment != 0 && rune == r.Comment {
+ return nil, r.skip('\n')
+ }
+ r.r.UnreadRune()
+
+ // At this point we have at least one field.
+ for {
+ haveField, delim, err := r.parseField()
+ if haveField {
+ fields = append(fields, r.field.String())
+ }
+ if delim == '\n' || err == os.EOF {
+ return fields, err
+ } else if err != nil {
+ return nil, err
+ }
+ }
+ panic("unreachable")
+}
+
+// parseField parses the next field in the record. The read field is
+// located in r.field. Delim is the first character not part of the field
+// (r.Comma or '\n').
+func (r *Reader) parseField() (haveField bool, delim int, err os.Error) {
+ r.field.Reset()
+
+ rune, err := r.readRune()
+ if err != nil {
+ // If we have EOF and are not at the start of a line
+ // then we return the empty field. We have already
+ // checked for trailing commas if needed.
+ if err == os.EOF && r.column != 0 {
+ return true, 0, err
+ }
+ return false, 0, err
+ }
+
+ if r.TrimLeadingSpace {
+ for unicode.IsSpace(rune) {
+ rune, err = r.readRune()
+ if err != nil {
+ return false, 0, err
+ }
+ }
+ }
+
+ switch rune {
+ case r.Comma:
+ // will check below
+
+ case '\n':
+ // We are a trailing empty field or a blank line
+ if r.column == 0 {
+ return false, rune, nil
+ }
+ return true, rune, nil
+
+ case '"':
+ // quoted field
+ Quoted:
+ for {
+ rune, err = r.readRune()
+ if err != nil {
+ if err == os.EOF {
+ if r.LazyQuotes {
+ return true, 0, err
+ }
+ return false, 0, r.error(ErrQuote)
+ }
+ return false, 0, err
+ }
+ switch rune {
+ case '"':
+ rune, err = r.readRune()
+ if err != nil || rune == r.Comma {
+ break Quoted
+ }
+ if rune == '\n' {
+ return true, rune, nil
+ }
+ if rune != '"' {
+ if !r.LazyQuotes {
+ r.column--
+ return false, 0, r.error(ErrQuote)
+ }
+ // accept the bare quote
+ r.field.WriteRune('"')
+ }
+ case '\n':
+ r.line++
+ r.column = -1
+ }
+ r.field.WriteRune(rune)
+ }
+
+ default:
+ // unquoted field
+ for {
+ r.field.WriteRune(rune)
+ rune, err = r.readRune()
+ if err != nil || rune == r.Comma {
+ break
+ }
+ if rune == '\n' {
+ return true, rune, nil
+ }
+ if !r.LazyQuotes && rune == '"' {
+ return false, 0, r.error(ErrBareQuote)
+ }
+ }
+ }
+
+ if err != nil {
+ if err == os.EOF {
+ return true, 0, err
+ }
+ return false, 0, err
+ }
+
+ if !r.TrailingComma {
+ // We don't allow trailing commas. See if we
+ // are at the end of the line (being mindful
+ // of trimming spaces).
+ c := r.column
+ rune, err = r.readRune()
+ if r.TrimLeadingSpace {
+ for unicode.IsSpace(rune) {
+ rune, err = r.readRune()
+ if err != nil {
+ break
+ }
+ }
+ }
+ if err == os.EOF || rune == '\n' {
+ r.column = c // report the comma
+ return false, 0, r.error(ErrTrailingComma)
+ }
+ r.unreadRune()
+ }
+ return true, rune, nil
+}
diff --git a/libgo/go/csv/reader_test.go b/libgo/go/csv/reader_test.go
new file mode 100644
index 00000000000..0068bad1db6
--- /dev/null
+++ b/libgo/go/csv/reader_test.go
@@ -0,0 +1,265 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package csv
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var readTests = []struct {
+ Name string
+ Input string
+ Output [][]string
+ UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1
+
+ // These fields are copied into the Reader
+ Comma int
+ Comment int
+ FieldsPerRecord int
+ LazyQuotes bool
+ TrailingComma bool
+ TrimLeadingSpace bool
+
+ Error string
+ Line int // Expected error line if != 0
+ Column int // Expected error column if line != 0
+}{
+ {
+ Name: "Simple",
+ Input: "a,b,c\n",
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "CRLF",
+ Input: "a,b\r\nc,d\r\n",
+ Output: [][]string{{"a", "b"}, {"c", "d"}},
+ },
+ {
+ Name: "BareCR",
+ Input: "a,b\rc,d\r\n",
+ Output: [][]string{{"a", "b\rc", "d"}},
+ },
+ {
+ Name: "RFC4180test",
+ UseFieldsPerRecord: true,
+ Input: `#field1,field2,field3
+"aaa","bb
+b","ccc"
+"a,a","b""bb","ccc"
+zzz,yyy,xxx
+`,
+ Output: [][]string{
+ {"#field1", "field2", "field3"},
+ {"aaa", "bb\nb", "ccc"},
+ {"a,a", `b"bb`, "ccc"},
+ {"zzz", "yyy", "xxx"},
+ },
+ },
+ {
+ Name: "NoEOLTest",
+ Input: "a,b,c",
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "Semicolon",
+ Comma: ';',
+ Input: "a;b;c\n",
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "MultiLine",
+ Input: `"two
+line","one line","three
+line
+field"`,
+ Output: [][]string{{"two\nline", "one line", "three\nline\nfield"}},
+ },
+ {
+ Name: "BlankLine",
+ Input: "a,b,c\n\nd,e,f\n\n",
+ Output: [][]string{
+ {"a", "b", "c"},
+ {"d", "e", "f"},
+ },
+ },
+ {
+ Name: "TrimSpace",
+ Input: " a, b, c\n",
+ TrimLeadingSpace: true,
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "LeadingSpace",
+ Input: " a, b, c\n",
+ Output: [][]string{{" a", " b", " c"}},
+ },
+ {
+ Name: "Comment",
+ Comment: '#',
+ Input: "#1,2,3\na,b,c\n#comment",
+ Output: [][]string{{"a", "b", "c"}},
+ },
+ {
+ Name: "NoComment",
+ Input: "#1,2,3\na,b,c",
+ Output: [][]string{{"#1", "2", "3"}, {"a", "b", "c"}},
+ },
+ {
+ Name: "LazyQuotes",
+ LazyQuotes: true,
+ Input: `a "word","1"2",a","b`,
+ Output: [][]string{{`a "word"`, `1"2`, `a"`, `b`}},
+ },
+ {
+ Name: "BareQuotes",
+ LazyQuotes: true,
+ Input: `a "word","1"2",a"`,
+ Output: [][]string{{`a "word"`, `1"2`, `a"`}},
+ },
+ {
+ Name: "BareDoubleQuotes",
+ LazyQuotes: true,
+ Input: `a""b,c`,
+ Output: [][]string{{`a""b`, `c`}},
+ },
+ {
+ Name: "BadDoubleQuotes",
+ Input: `a""b,c`,
+ Output: [][]string{{`a""b`, `c`}},
+ Error: `bare " in non-quoted-field`, Line: 1, Column: 1,
+ },
+ {
+ Name: "TrimQuote",
+ Input: ` "a"," b",c`,
+ TrimLeadingSpace: true,
+ Output: [][]string{{"a", " b", "c"}},
+ },
+ {
+ Name: "BadBareQuote",
+ Input: `a "word","b"`,
+ Error: `bare " in non-quoted-field`, Line: 1, Column: 2,
+ },
+ {
+ Name: "BadTrailingQuote",
+ Input: `"a word",b"`,
+ Error: `bare " in non-quoted-field`, Line: 1, Column: 10,
+ },
+ {
+ Name: "ExtraneousQuote",
+ Input: `"a "word","b"`,
+ Error: `extraneous " in field`, Line: 1, Column: 3,
+ },
+ {
+ Name: "BadFieldCount",
+ UseFieldsPerRecord: true,
+ Input: "a,b,c\nd,e",
+ Error: "wrong number of fields", Line: 2,
+ },
+ {
+ Name: "BadFieldCount1",
+ UseFieldsPerRecord: true,
+ FieldsPerRecord: 2,
+ Input: `a,b,c`,
+ Error: "wrong number of fields", Line: 1,
+ },
+ {
+ Name: "FieldCount",
+ Input: "a,b,c\nd,e",
+ Output: [][]string{{"a", "b", "c"}, {"d", "e"}},
+ },
+ {
+ Name: "BadTrailingCommaEOF",
+ Input: "a,b,c,",
+ Error: "extra delimiter at end of line", Line: 1, Column: 5,
+ },
+ {
+ Name: "BadTrailingCommaEOL",
+ Input: "a,b,c,\n",
+ Error: "extra delimiter at end of line", Line: 1, Column: 5,
+ },
+ {
+ Name: "BadTrailingCommaSpaceEOF",
+ TrimLeadingSpace: true,
+ Input: "a,b,c, ",
+ Error: "extra delimiter at end of line", Line: 1, Column: 5,
+ },
+ {
+ Name: "BadTrailingCommaSpaceEOL",
+ TrimLeadingSpace: true,
+ Input: "a,b,c, \n",
+ Error: "extra delimiter at end of line", Line: 1, Column: 5,
+ },
+ {
+ Name: "BadTrailingCommaLine3",
+ TrimLeadingSpace: true,
+ Input: "a,b,c\nd,e,f\ng,hi,",
+ Error: "extra delimiter at end of line", Line: 3, Column: 4,
+ },
+ {
+ Name: "NotTrailingComma3",
+ Input: "a,b,c, \n",
+ Output: [][]string{{"a", "b", "c", " "}},
+ },
+ {
+ Name: "CommaFieldTest",
+ TrailingComma: true,
+ Input: `x,y,z,w
+x,y,z,
+x,y,,
+x,,,
+,,,
+"x","y","z","w"
+"x","y","z",""
+"x","y","",""
+"x","","",""
+"","","",""
+`,
+ Output: [][]string{
+ {"x", "y", "z", "w"},
+ {"x", "y", "z", ""},
+ {"x", "y", "", ""},
+ {"x", "", "", ""},
+ {"", "", "", ""},
+ {"x", "y", "z", "w"},
+ {"x", "y", "z", ""},
+ {"x", "y", "", ""},
+ {"x", "", "", ""},
+ {"", "", "", ""},
+ },
+ },
+}
+
+func TestRead(t *testing.T) {
+ for _, tt := range readTests {
+ r := NewReader(strings.NewReader(tt.Input))
+ r.Comment = tt.Comment
+ if tt.UseFieldsPerRecord {
+ r.FieldsPerRecord = tt.FieldsPerRecord
+ } else {
+ r.FieldsPerRecord = -1
+ }
+ r.LazyQuotes = tt.LazyQuotes
+ r.TrailingComma = tt.TrailingComma
+ r.TrimLeadingSpace = tt.TrimLeadingSpace
+ if tt.Comma != 0 {
+ r.Comma = tt.Comma
+ }
+ out, err := r.ReadAll()
+ perr, _ := err.(*ParseError)
+ if tt.Error != "" {
+ if err == nil || !strings.Contains(err.String(), tt.Error) {
+ t.Errorf("%s: error %v, want error %q", tt.Name, err, tt.Error)
+ } else if tt.Line != 0 && (tt.Line != perr.Line || tt.Column != perr.Column) {
+ t.Errorf("%s: error at %d:%d expected %d:%d", tt.Name, perr.Line, perr.Column, tt.Line, tt.Column)
+ }
+ } else if err != nil {
+ t.Errorf("%s: unexpected error %v", tt.Name, err)
+ } else if !reflect.DeepEqual(out, tt.Output) {
+ t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output)
+ }
+ }
+}
diff --git a/libgo/go/csv/writer.go b/libgo/go/csv/writer.go
new file mode 100644
index 00000000000..ccf703f0f8c
--- /dev/null
+++ b/libgo/go/csv/writer.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package csv
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// A Writer writes records to a CSV encoded file.
+//
+// As returned by NewWriter, a Writer writes records terminated by a
+// newline and uses ',' as the field delimiter. The exported fields can be
+// changed to customize the details before the first call to Write or WriteAll.
+//
+// Comma is the field delimiter.
+//
+// If UseCRLF is true, the Writer ends each record with \r\n instead of \n.
+type Writer struct {
+ Comma int // Field delimiter (set to to ',' by NewWriter)
+ UseCRLF bool // True to use \r\n as the line terminator
+ w *bufio.Writer
+}
+
+// NewWriter returns a new Writer that writes to w.
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{
+ Comma: ',',
+ w: bufio.NewWriter(w),
+ }
+}
+
+// Writer writes a single CSV record to w along with any necessary quoting.
+// A record is a slice of strings with each string being one field.
+func (w *Writer) Write(record []string) (err os.Error) {
+ for n, field := range record {
+ if n > 0 {
+ if _, err = w.w.WriteRune(w.Comma); err != nil {
+ return
+ }
+ }
+
+ // If we don't have to have a quoted field then just
+ // write out the field and continue to the next field.
+ if !w.fieldNeedsQuotes(field) {
+ if _, err = w.w.WriteString(field); err != nil {
+ return
+ }
+ continue
+ }
+ if err = w.w.WriteByte('"'); err != nil {
+ return
+ }
+
+ for _, rune := range field {
+ switch rune {
+ case '"':
+ _, err = w.w.WriteString(`""`)
+ case '\r':
+ if !w.UseCRLF {
+ err = w.w.WriteByte('\r')
+ }
+ case '\n':
+ if w.UseCRLF {
+ _, err = w.w.WriteString("\r\n")
+ } else {
+ err = w.w.WriteByte('\n')
+ }
+ default:
+ _, err = w.w.WriteRune(rune)
+ }
+ if err != nil {
+ return
+ }
+ }
+
+ if err = w.w.WriteByte('"'); err != nil {
+ return
+ }
+ }
+ if w.UseCRLF {
+ _, err = w.w.WriteString("\r\n")
+ } else {
+ err = w.w.WriteByte('\n')
+ }
+ return
+}
+
+// Flush writes any buffered data to the underlying io.Writer.
+func (w *Writer) Flush() {
+ w.w.Flush()
+}
+
+// WriteAll writes multiple CSV records to w using Write and then calls Flush.
+func (w *Writer) WriteAll(records [][]string) (err os.Error) {
+ for _, record := range records {
+ err = w.Write(record)
+ if err != nil {
+ break
+ }
+ }
+ w.Flush()
+ return nil
+}
+
+// fieldNeedsQuotes returns true if our field must be enclosed in quotes.
+// Empty fields, files with a Comma, fields with a quote or newline, and
+// fields which start with a space must be enclosed in quotes.
+func (w *Writer) fieldNeedsQuotes(field string) bool {
+ if len(field) == 0 || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+ return true
+ }
+
+ rune, _ := utf8.DecodeRuneInString(field)
+ return unicode.IsSpace(rune)
+}
diff --git a/libgo/go/csv/writer_test.go b/libgo/go/csv/writer_test.go
new file mode 100644
index 00000000000..578959007fd
--- /dev/null
+++ b/libgo/go/csv/writer_test.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.
+
+package csv
+
+import (
+ "bytes"
+ "testing"
+)
+
+var writeTests = []struct {
+ Input [][]string
+ Output string
+ UseCRLF bool
+}{
+ {Input: [][]string{{"abc"}}, Output: "abc\n"},
+ {Input: [][]string{{"abc"}}, Output: "abc\r\n", UseCRLF: true},
+ {Input: [][]string{{`"abc"`}}, Output: `"""abc"""` + "\n"},
+ {Input: [][]string{{`a"b`}}, Output: `"a""b"` + "\n"},
+ {Input: [][]string{{`"a"b"`}}, Output: `"""a""b"""` + "\n"},
+ {Input: [][]string{{" abc"}}, Output: `" abc"` + "\n"},
+ {Input: [][]string{{"abc,def"}}, Output: `"abc,def"` + "\n"},
+ {Input: [][]string{{"abc", "def"}}, Output: "abc,def\n"},
+ {Input: [][]string{{"abc"}, {"def"}}, Output: "abc\ndef\n"},
+ {Input: [][]string{{"abc\ndef"}}, Output: "\"abc\ndef\"\n"},
+ {Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true},
+}
+
+func TestWrite(t *testing.T) {
+ for n, tt := range writeTests {
+ b := &bytes.Buffer{}
+ f := NewWriter(b)
+ f.UseCRLF = tt.UseCRLF
+ err := f.WriteAll(tt.Input)
+ if err != nil {
+ t.Errorf("Unexpected error: %s\n", err)
+ }
+ out := b.String()
+ if out != tt.Output {
+ t.Errorf("#%d: out=%q want %q", n, out, tt.Output)
+ }
+ }
+}
diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go
index 902a545f860..f35365ebeb0 100644
--- a/libgo/go/debug/dwarf/type.go
+++ b/libgo/go/debug/dwarf/type.go
@@ -352,8 +352,8 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
}
}
if ndim == 0 {
- err = DecodeError{"info", e.Offset, "missing dimension for array"}
- goto Error
+ // LLVM generates this for x[].
+ t.Count = -1
}
case TagBaseType:
@@ -523,7 +523,7 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
// Attributes:
// AttrType: type of return value if any
// AttrName: possible name of type [ignored]
- // AttrPrototyped: whether used ANSI C prototye [ignored]
+ // AttrPrototyped: whether used ANSI C prototype [ignored]
// Children:
// TagFormalParameter: typed parameter
// AttrType: type of parameter
@@ -566,12 +566,13 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
goto Error
}
- b, ok := e.Val(AttrByteSize).(int64)
- if !ok {
- b = -1
+ {
+ b, ok := e.Val(AttrByteSize).(int64)
+ if !ok {
+ b = -1
+ }
+ typ.Common().ByteSize = b
}
- typ.Common().ByteSize = b
-
return typ, nil
Error:
diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go
index e01f7353a4d..b9470a4fcb4 100644
--- a/libgo/go/debug/dwarf/type_test.go
+++ b/libgo/go/debug/dwarf/type_test.go
@@ -58,7 +58,6 @@ func machoData(t *testing.T, name string) *Data {
return d
}
-
func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf")) }
func TestTypedefsMachO(t *testing.T) {
diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go
index 5d45b24863d..c71b230bd95 100644
--- a/libgo/go/debug/elf/elf.go
+++ b/libgo/go/debug/elf/elf.go
@@ -1289,7 +1289,6 @@ func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings,
// 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. */
@@ -1455,7 +1454,6 @@ 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. */
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index 9ae8b413d91..a0ddb1fc7ad 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -81,7 +81,7 @@ func (s *Section) Data() ([]byte, os.Error) {
// specified link value.
func (f *File) stringTable(link uint32) ([]byte, os.Error) {
if link <= 0 || link >= uint32(len(f.Sections)) {
- return nil, os.ErrorString("section has invalid string table link")
+ return nil, os.NewError("section has invalid string table link")
}
return f.Sections[link].Data()
}
@@ -93,6 +93,7 @@ func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<
type ProgHeader struct {
Type ProgType
Flags ProgFlag
+ Off uint64
Vaddr uint64
Paddr uint64
Filesz uint64
@@ -224,6 +225,8 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
f.ABIVersion = ident[EI_ABIVERSION]
// Read ELF file header
+ var phoff int64
+ var phentsize, phnum int
var shoff int64
var shentsize, shnum, shstrndx int
shstrndx = -1
@@ -239,6 +242,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
if v := Version(hdr.Version); v != f.Version {
return nil, &FormatError{0, "mismatched ELF version", v}
}
+ phoff = int64(hdr.Phoff)
+ phentsize = int(hdr.Phentsize)
+ phnum = int(hdr.Phnum)
shoff = int64(hdr.Shoff)
shentsize = int(hdr.Shentsize)
shnum = int(hdr.Shnum)
@@ -254,6 +260,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
if v := Version(hdr.Version); v != f.Version {
return nil, &FormatError{0, "mismatched ELF version", v}
}
+ phoff = int64(hdr.Phoff)
+ phentsize = int(hdr.Phentsize)
+ phnum = int(hdr.Phnum)
shoff = int64(hdr.Shoff)
shentsize = int(hdr.Shentsize)
shnum = int(hdr.Shnum)
@@ -264,7 +273,47 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
}
// Read program headers
- // TODO
+ f.Progs = make([]*Prog, phnum)
+ for i := 0; i < phnum; i++ {
+ off := phoff + int64(i)*int64(phentsize)
+ sr.Seek(off, os.SEEK_SET)
+ p := new(Prog)
+ switch f.Class {
+ case ELFCLASS32:
+ ph := new(Prog32)
+ if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
+ return nil, err
+ }
+ p.ProgHeader = ProgHeader{
+ Type: ProgType(ph.Type),
+ Flags: ProgFlag(ph.Flags),
+ Off: uint64(ph.Off),
+ Vaddr: uint64(ph.Vaddr),
+ Paddr: uint64(ph.Paddr),
+ Filesz: uint64(ph.Filesz),
+ Memsz: uint64(ph.Memsz),
+ Align: uint64(ph.Align),
+ }
+ case ELFCLASS64:
+ ph := new(Prog64)
+ if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
+ return nil, err
+ }
+ p.ProgHeader = ProgHeader{
+ Type: ProgType(ph.Type),
+ Flags: ProgFlag(ph.Flags),
+ Off: uint64(ph.Off),
+ Vaddr: uint64(ph.Vaddr),
+ Paddr: uint64(ph.Paddr),
+ Filesz: uint64(ph.Filesz),
+ Memsz: uint64(ph.Memsz),
+ Align: uint64(ph.Align),
+ }
+ }
+ p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
+ p.ReaderAt = p.sr
+ f.Progs[i] = p
+ }
// Read section headers
f.Sections = make([]*Section, shnum)
@@ -341,27 +390,27 @@ func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) {
return f.getSymbols32(typ)
}
- return nil, nil, os.ErrorString("not implemented")
+ return nil, nil, os.NewError("not implemented")
}
func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
- return nil, nil, os.ErrorString("no symbol section")
+ return nil, nil, os.NewError("no symbol section")
}
data, err := symtabSection.Data()
if err != nil {
- return nil, nil, os.ErrorString("cannot load symbol section")
+ return nil, nil, os.NewError("cannot load symbol section")
}
symtab := bytes.NewBuffer(data)
if symtab.Len()%Sym32Size != 0 {
- return nil, nil, os.ErrorString("length of symbol section is not a multiple of SymSize")
+ return nil, nil, os.NewError("length of symbol section is not a multiple of SymSize")
}
strdata, err := f.stringTable(symtabSection.Link)
if err != nil {
- return nil, nil, os.ErrorString("cannot load string table section")
+ return nil, nil, os.NewError("cannot load string table section")
}
// The first entry is all zeros.
@@ -390,21 +439,21 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
- return nil, nil, os.ErrorString("no symbol section")
+ return nil, nil, os.NewError("no symbol section")
}
data, err := symtabSection.Data()
if err != nil {
- return nil, nil, os.ErrorString("cannot load symbol section")
+ return nil, nil, os.NewError("cannot load symbol section")
}
symtab := bytes.NewBuffer(data)
if symtab.Len()%Sym64Size != 0 {
- return nil, nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size")
+ return nil, nil, os.NewError("length of symbol section is not a multiple of Sym64Size")
}
strdata, err := f.stringTable(symtabSection.Link)
if err != nil {
- return nil, nil, os.ErrorString("cannot load string table section")
+ return nil, nil, os.NewError("cannot load string table section")
}
// The first entry is all zeros.
@@ -462,12 +511,12 @@ func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
return f.applyRelocationsAMD64(dst, rels)
}
- return os.ErrorString("not implemented")
+ return os.NewError("not implemented")
}
func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
if len(rels)%Sym64Size != 0 {
- return os.ErrorString("length of relocation section is not a multiple of Sym64Size")
+ return os.NewError("length of relocation section is not a multiple of Sym64Size")
}
symbols, _, err := f.getSymbols(SHT_SYMTAB)
@@ -546,6 +595,12 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
}
+// Symbols returns the symbol table for f.
+func (f *File) Symbols() ([]Symbol, os.Error) {
+ sym, _, err := f.getSymbols(SHT_SYMTAB)
+ return sym, err
+}
+
type ImportedSymbol struct {
Name string
Version string
diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go
index 84068ea12a6..98f2723c86e 100644
--- a/libgo/go/debug/elf/file_test.go
+++ b/libgo/go/debug/elf/file_test.go
@@ -7,7 +7,10 @@ package elf
import (
"debug/dwarf"
"encoding/binary"
+ "net"
+ "os"
"reflect"
+ "runtime"
"testing"
)
@@ -15,6 +18,7 @@ type fileTest struct {
file string
hdr FileHeader
sections []SectionHeader
+ progs []ProgHeader
}
var fileTests = []fileTest{
@@ -53,6 +57,13 @@ var fileTests = []fileTest{
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
},
+ []ProgHeader{
+ {PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
+ {PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
+ {PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
+ {PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
+ {PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
+ },
},
{
"testdata/gcc-amd64-linux-exec",
@@ -96,6 +107,16 @@ var fileTests = []fileTest{
{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
},
+ []ProgHeader{
+ {PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
+ {PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
+ {PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
+ {PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
+ {PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
+ {PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
+ {PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
+ {PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
+ },
},
}
@@ -121,11 +142,25 @@ func TestOpen(t *testing.T) {
t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
}
}
+ for i, p := range f.Progs {
+ if i >= len(tt.progs) {
+ break
+ }
+ ph := &tt.progs[i]
+ if !reflect.DeepEqual(&p.ProgHeader, ph) {
+ t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph)
+ }
+ }
tn := len(tt.sections)
fn := len(f.Sections)
if tn != fn {
t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
}
+ tn = len(tt.progs)
+ fn = len(f.Progs)
+ if tn != fn {
+ t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
+ }
}
}
@@ -136,15 +171,15 @@ type relocationTest struct {
var relocationTests = []relocationTest{
{
- "testdata/go-relocation-test-gcc441-x86-64.o",
+ "testdata/go-relocation-test-gcc441-x86-64.obj",
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
{
- "testdata/go-relocation-test-gcc441-x86.o",
+ "testdata/go-relocation-test-gcc441-x86.obj",
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
{
- "testdata/go-relocation-test-gcc424-x86-64.o",
+ "testdata/go-relocation-test-gcc424-x86-64.obj",
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
}
@@ -178,3 +213,32 @@ func TestDWARFRelocations(t *testing.T) {
}
}
}
+
+func TestNoSectionOverlaps(t *testing.T) {
+ // Ensure 6l outputs sections without overlaps.
+ if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
+ return // not ELF
+ }
+ _ = net.ResolveIPAddr // force dynamic linkage
+ f, err := Open(os.Args[0])
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ for i, si := range f.Sections {
+ sih := si.SectionHeader
+ if sih.Type == SHT_NOBITS {
+ continue
+ }
+ for j, sj := range f.Sections {
+ sjh := sj.SectionHeader
+ if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
+ continue
+ }
+ if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
+ t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
+ sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
+ }
+ }
+ }
+}
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.obj
index a7c6d6e562c..a7c6d6e562c 100644
--- 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.obj
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.obj
index 2d37ab6e6e1..2d37ab6e6e1 100644
--- 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.obj
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.obj
index 0d59fe303b6..0d59fe303b6 100644
--- a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o
+++ b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.obj
Binary files differ
diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go
index a777d873cf2..721a4c4168d 100644
--- a/libgo/go/debug/macho/file.go
+++ b/libgo/go/debug/macho/file.go
@@ -184,7 +184,7 @@ func (f *File) Close() os.Error {
return err
}
-// NewFile creates a new File for acecssing a Mach-O binary in an underlying reader.
+// NewFile creates a new File for accessing 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)
diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go
index 6a14e50f960..d86d916f505 100644
--- a/libgo/go/debug/pe/file.go
+++ b/libgo/go/debug/pe/file.go
@@ -35,7 +35,6 @@ type SectionHeader struct {
Characteristics uint32
}
-
type Section struct {
SectionHeader
@@ -69,7 +68,6 @@ func (s *Section) Data() ([]byte, os.Error) {
// 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
@@ -112,7 +110,7 @@ func (f *File) Close() os.Error {
return err
}
-// NewFile creates a new File for acecssing a PE binary in an underlying reader.
+// NewFile creates a new File for accessing 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)
@@ -245,6 +243,7 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
// satisfied by other libraries at dynamic load time.
// It does not return weak symbols.
func (f *File) ImportedSymbols() ([]string, os.Error) {
+ pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
ds := f.Section(".idata")
if ds == nil {
// not dynamic, so no libraries
@@ -274,17 +273,31 @@ func (f *File) ImportedSymbols() ([]string, os.Error) {
// seek to OriginalFirstThunk
d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
for len(d) > 0 {
- va := binary.LittleEndian.Uint32(d[0:4])
- d = d[4:]
- if va == 0 {
- break
- }
- if va&0x80000000 > 0 { // is Ordinal
- // TODO add dynimport ordinal support.
- //ord := va&0x0000FFFF
- } else {
- fn, _ := getString(names, int(va-ds.VirtualAddress+2))
- all = append(all, fn+":"+dt.dll)
+ if pe64 { // 64bit
+ va := binary.LittleEndian.Uint64(d[0:8])
+ d = d[8:]
+ if va == 0 {
+ break
+ }
+ if va&0x8000000000000000 > 0 { // is Ordinal
+ // TODO add dynimport ordinal support.
+ } else {
+ fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2))
+ all = append(all, fn+":"+dt.dll)
+ }
+ } else { // 32bit
+ va := binary.LittleEndian.Uint32(d[0:4])
+ d = d[4:]
+ if va == 0 {
+ break
+ }
+ if va&0x80000000 > 0 { // is Ordinal
+ // TODO add dynimport ordinal support.
+ //ord := va&0x0000FFFF
+ } else {
+ fn, _ := getString(names, int(va-ds.VirtualAddress+2))
+ all = append(all, fn+":"+dt.dll)
+ }
}
}
}
diff --git a/libgo/go/debug/proc/proc.go b/libgo/go/debug/proc/proc.go
deleted file mode 100644
index d89649cf887..00000000000
--- a/libgo/go/debug/proc/proc.go
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package 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
deleted file mode 100644
index 49f0a5361fb..00000000000
--- a/libgo/go/debug/proc/proc_darwin.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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 StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
- return Attach(0)
-}
diff --git a/libgo/go/debug/proc/proc_freebsd.go b/libgo/go/debug/proc/proc_freebsd.go
deleted file mode 100644
index 4df07c365af..00000000000
--- a/libgo/go/debug/proc/proc_freebsd.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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 StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
- return Attach(0)
-}
diff --git a/libgo/go/debug/proc/proc_linux.go b/libgo/go/debug/proc/proc_linux.go
deleted file mode 100644
index 17c8fa529f5..00000000000
--- a/libgo/go/debug/proc/proc_linux.go
+++ /dev/null
@@ -1,1322 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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)
- 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
-}
-
-// StartProcess forks the current process and execs argv0, stopping the
-// new process after the exec syscall. See os.StartProcess for additional
-// details.
-func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
- sysattr := &syscall.ProcAttr{
- Dir: attr.Dir,
- Env: attr.Env,
- Ptrace: true,
- }
- p := newProcess(-1)
-
- // Create array of integer (system) fds.
- intfd := make([]int, len(attr.Files))
- for i, f := range attr.Files {
- if f == nil {
- intfd[i] = -1
- } else {
- intfd[i] = f.Fd()
- }
- }
- sysattr.Files = intfd
-
- // Fork from the monitor thread so we get the right tracer pid.
- err := p.do(func() os.Error {
- pid, _, errno := syscall.StartProcess(argv0, argv, sysattr)
- 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_windows.go b/libgo/go/debug/proc/proc_windows.go
deleted file mode 100644
index 661474b67aa..00000000000
--- a/libgo/go/debug/proc/proc_windows.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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 StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
- return Attach(0)
-}
diff --git a/libgo/go/debug/proc/regs_darwin_386.go b/libgo/go/debug/proc/regs_darwin_386.go
deleted file mode 100644
index 60c9ac719e9..00000000000
--- a/libgo/go/debug/proc/regs_darwin_386.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/libgo/go/debug/proc/regs_darwin_amd64.go b/libgo/go/debug/proc/regs_darwin_amd64.go
deleted file mode 100644
index 60c9ac719e9..00000000000
--- a/libgo/go/debug/proc/regs_darwin_amd64.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/libgo/go/debug/proc/regs_freebsd_386.go b/libgo/go/debug/proc/regs_freebsd_386.go
deleted file mode 100644
index 60c9ac719e9..00000000000
--- a/libgo/go/debug/proc/regs_freebsd_386.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/libgo/go/debug/proc/regs_freebsd_amd64.go b/libgo/go/debug/proc/regs_freebsd_amd64.go
deleted file mode 100644
index 60c9ac719e9..00000000000
--- a/libgo/go/debug/proc/regs_freebsd_amd64.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/libgo/go/debug/proc/regs_linux_386.go b/libgo/go/debug/proc/regs_linux_386.go
deleted file mode 100644
index b4a9769db55..00000000000
--- a/libgo/go/debug/proc/regs_linux_386.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 381be29b179..00000000000
--- a/libgo/go/debug/proc/regs_linux_amd64.go
+++ /dev/null
@@ -1,191 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index ec78cbcf259..00000000000
--- a/libgo/go/debug/proc/regs_linux_arm.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 60c9ac719e9..00000000000
--- a/libgo/go/debug/proc/regs_windows_386.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/libgo/go/debug/proc/regs_windows_amd64.go b/libgo/go/debug/proc/regs_windows_amd64.go
deleted file mode 100644
index 60c9ac719e9..00000000000
--- a/libgo/go/debug/proc/regs_windows_amd64.go
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package proc
diff --git a/libgo/go/ebnf/ebnf.go b/libgo/go/ebnf/ebnf.go
index 7918c4593bb..69da1176725 100644
--- a/libgo/go/ebnf/ebnf.go
+++ b/libgo/go/ebnf/ebnf.go
@@ -5,10 +5,10 @@
// Package ebnf is a library for EBNF grammars. The input is text ([]byte)
// satisfying the following grammar (represented itself in EBNF):
//
-// Production = name "=" Expression "." .
+// Production = name "=" [ Expression ] "." .
// Expression = Alternative { "|" Alternative } .
// Alternative = Term { Term } .
-// Term = name | token [ "..." token ] | Group | Option | Repetition .
+// Term = name | token [ "…" token ] | Group | Option | Repetition .
// Group = "(" Expression ")" .
// Option = "[" Expression "]" .
// Repetition = "{" Expression "}" .
@@ -30,7 +30,6 @@ import (
"utf8"
)
-
// ----------------------------------------------------------------------------
// Internal representation
@@ -82,6 +81,12 @@ type (
Body Expression // {body}
}
+ // A Bad node stands for pieces of source code that lead to a parse error.
+ Bad struct {
+ TokPos token.Pos
+ Error string // parser error message
+ }
+
// A Production node represents an EBNF production.
Production struct {
Name *Name
@@ -94,7 +99,6 @@ type (
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 }
@@ -103,9 +107,9 @@ 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 *Bad) Pos() token.Pos { return x.TokPos }
func (x *Production) Pos() token.Pos { return x.Name.Pos() }
-
// ----------------------------------------------------------------------------
// Grammar verification
@@ -114,7 +118,6 @@ func isLexical(name string) bool {
return !unicode.IsUpper(ch)
}
-
type verifier struct {
fset *token.FileSet
scanner.ErrorVector
@@ -123,12 +126,10 @@ type verifier struct {
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 {
@@ -137,7 +138,6 @@ func (v *verifier) push(prod *Production) {
}
}
-
func (v *verifier) verifyChar(x *Token) int {
s := x.String
if utf8.RuneCountInString(s) != 1 {
@@ -148,7 +148,6 @@ func (v *verifier) verifyChar(x *Token) int {
return ch
}
-
func (v *verifier) verifyExpr(expr Expression, lexical bool) {
switch x := expr.(type) {
case nil:
@@ -193,7 +192,6 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) {
}
}
-
func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) {
// find root production
root, found := grammar[start]
@@ -233,7 +231,6 @@ func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) {
}
}
-
// Verify checks that:
// - all productions used are defined
// - all productions defined are used when beginning at start
diff --git a/libgo/go/ebnf/ebnf_test.go b/libgo/go/ebnf/ebnf_test.go
index e77cf64adfa..b086facc3ed 100644
--- a/libgo/go/ebnf/ebnf_test.go
+++ b/libgo/go/ebnf/ebnf_test.go
@@ -10,11 +10,9 @@ import (
"testing"
)
-
var fset = token.NewFileSet()
-
-var grammars = []string{
+var goodGrammars = []string{
`Program = .`,
`Program = foo .
@@ -22,7 +20,7 @@ var grammars = []string{
`Program = "a" | "b" "c" .`,
- `Program = "a" ... "z" .`,
+ `Program = "a" … "z" .`,
`Program = Song .
Song = { Note } .
@@ -37,8 +35,18 @@ var grammars = []string{
ti = "b" .`,
}
+var badGrammars = []string{
+ `Program = | .`,
+ `Program = | b .`,
+ `Program = a … b .`,
+ `Program = "a" … .`,
+ `Program = … "b" .`,
+ `Program = () .`,
+ `Program = [] .`,
+ `Program = {} .`,
+}
-func check(t *testing.T, filename string, src []byte) {
+func checkGood(t *testing.T, filename string, src []byte) {
grammar, err := Parse(fset, filename, src)
if err != nil {
t.Errorf("Parse(%s) failed: %v", src, err)
@@ -48,25 +56,32 @@ func check(t *testing.T, filename string, src []byte) {
}
}
+func checkBad(t *testing.T, filename string, src []byte) {
+ _, err := Parse(fset, filename, src)
+ if err == nil {
+ t.Errorf("Parse(%s) should have failed", src)
+ }
+}
func TestGrammars(t *testing.T) {
- for _, src := range grammars {
- check(t, "", []byte(src))
+ for _, src := range goodGrammars {
+ checkGood(t, "", []byte(src))
+ }
+ for _, src := range badGrammars {
+ checkBad(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)
+ checkGood(t, filename, src)
}
}
diff --git a/libgo/go/ebnf/parser.go b/libgo/go/ebnf/parser.go
index 818168e111d..ef2fac0000f 100644
--- a/libgo/go/ebnf/parser.go
+++ b/libgo/go/ebnf/parser.go
@@ -11,7 +11,6 @@ import (
"strconv"
)
-
type parser struct {
fset *token.FileSet
scanner.ErrorVector
@@ -21,7 +20,6 @@ type parser struct {
lit string // token literal
}
-
func (p *parser) next() {
p.pos, p.tok, p.lit = p.scanner.Scan()
if p.tok.IsKeyword() {
@@ -31,12 +29,10 @@ func (p *parser) next() {
}
}
-
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 {
@@ -50,7 +46,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
p.error(pos, msg)
}
-
func (p *parser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
@@ -60,7 +55,6 @@ func (p *parser) expect(tok token.Token) token.Pos {
return pos
}
-
func (p *parser) parseIdentifier() *Name {
pos := p.pos
name := p.lit
@@ -68,7 +62,6 @@ func (p *parser) parseIdentifier() *Name {
return &Name{pos, name}
}
-
func (p *parser) parseToken() *Token {
pos := p.pos
value := ""
@@ -84,7 +77,7 @@ func (p *parser) parseToken() *Token {
return &Token{pos, value}
}
-
+// ParseTerm returns nil if no term was found.
func (p *parser) parseTerm() (x Expression) {
pos := p.pos
@@ -95,7 +88,8 @@ func (p *parser) parseTerm() (x Expression) {
case token.STRING:
tok := p.parseToken()
x = tok
- if p.tok == token.ELLIPSIS {
+ const ellipsis = "…" // U+2026, the horizontal ellipsis character
+ if p.tok == token.ILLEGAL && p.lit == ellipsis {
p.next()
x = &Range{tok, p.parseToken()}
}
@@ -119,7 +113,6 @@ func (p *parser) parseTerm() (x Expression) {
return x
}
-
func (p *parser) parseSequence() Expression {
var list Sequence
@@ -130,7 +123,8 @@ func (p *parser) parseSequence() Expression {
// no need for a sequence if list.Len() < 2
switch len(list) {
case 0:
- return nil
+ p.errorExpected(p.pos, "term")
+ return &Bad{p.pos, "term expected"}
case 1:
return list[0]
}
@@ -138,46 +132,42 @@ func (p *parser) parseSequence() Expression {
return list
}
-
func (p *parser) parseExpression() Expression {
var list Alternative
for {
- if x := p.parseSequence(); x != nil {
- list = append(list, x)
- }
+ list = append(list, p.parseSequence())
if p.tok != token.OR {
break
}
p.next()
}
+ // len(list) > 0
// no need for an Alternative node if list.Len() < 2
- switch len(list) {
- case 0:
- return nil
- case 1:
+ if len(list) == 1 {
return list[0]
}
return list
}
-
func (p *parser) parseProduction() *Production {
name := p.parseIdentifier()
p.expect(token.ASSIGN)
- expr := p.parseExpression()
+ var expr Expression
+ if p.tok != token.PERIOD {
+ 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.scanner.Init(fset.AddFile(filename, fset.Base(), len(src)), src, p, scanner.AllowIllegalChars)
p.next() // initializes pos, tok, lit
grammar := make(Grammar)
@@ -194,7 +184,6 @@ func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar
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
diff --git a/libgo/go/encoding/base32/base32_test.go b/libgo/go/encoding/base32/base32_test.go
index 792e4dc635d..3fa1c2b2669 100644
--- a/libgo/go/encoding/base32/base32_test.go
+++ b/libgo/go/encoding/base32/base32_test.go
@@ -25,7 +25,6 @@ var pairs = []testpair{
{"fooba", "MZXW6YTB"},
{"foobar", "MZXW6YTBOI======"},
-
// Wikipedia examples, converted to base32
{"sure.", "ON2XEZJO"},
{"sure", "ON2XEZI="},
diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go
index 496129798cd..c6b2a13e4a4 100644
--- a/libgo/go/encoding/base64/base64.go
+++ b/libgo/go/encoding/base64/base64.go
@@ -106,6 +106,13 @@ func (enc *Encoding) Encode(dst, src []byte) {
}
}
+// EncodeToString returns the base64 encoding of src.
+func (enc *Encoding) EncodeToString(src []byte) string {
+ buf := make([]byte, enc.EncodedLen(len(src)))
+ enc.Encode(buf, src)
+ return string(buf)
+}
+
type encoder struct {
err os.Error
enc *Encoding
@@ -260,6 +267,13 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) {
return
}
+// DecodeString returns the bytes represented by the base64 string s.
+func (enc *Encoding) DecodeString(s string) ([]byte, os.Error) {
+ dbuf := make([]byte, enc.DecodedLen(len(s)))
+ n, err := enc.Decode(dbuf, []byte(s))
+ return dbuf[:n], err
+}
+
type decoder struct {
err os.Error
enc *Encoding
diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go
index de41e704b9f..c163dae842d 100644
--- a/libgo/go/encoding/base64/base64_test.go
+++ b/libgo/go/encoding/base64/base64_test.go
@@ -56,9 +56,8 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool {
func TestEncode(t *testing.T) {
for _, p := range pairs {
- buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded)))
- StdEncoding.Encode(buf, []byte(p.decoded))
- testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+ got := StdEncoding.EncodeToString([]byte(p.decoded))
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded)
}
}
@@ -102,6 +101,10 @@ func TestDecode(t *testing.T) {
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)
+
+ dbuf, err = StdEncoding.DecodeString(p.encoded)
+ testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, os.Error(nil))
+ testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
}
}
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
index a01d0e02464..8e55cb23b7c 100644
--- a/libgo/go/encoding/binary/binary.go
+++ b/libgo/go/encoding/binary/binary.go
@@ -125,6 +125,35 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// 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 {
+ // Fast path for basic types.
+ if n := intDestSize(data); n != 0 {
+ var b [8]byte
+ bs := b[:n]
+ if _, err := io.ReadFull(r, bs); err != nil {
+ return err
+ }
+ switch v := data.(type) {
+ case *int8:
+ *v = int8(b[0])
+ case *uint8:
+ *v = b[0]
+ case *int16:
+ *v = int16(order.Uint16(bs))
+ case *uint16:
+ *v = order.Uint16(bs)
+ case *int32:
+ *v = int32(order.Uint32(bs))
+ case *uint32:
+ *v = order.Uint32(bs)
+ case *int64:
+ *v = int64(order.Uint64(bs))
+ case *uint64:
+ *v = order.Uint64(bs)
+ }
+ return nil
+ }
+
+ // Fallback to reflect-based.
var v reflect.Value
switch d := reflect.ValueOf(data); d.Kind() {
case reflect.Ptr:
@@ -155,6 +184,63 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
// 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 {
+ // Fast path for basic types.
+ var b [8]byte
+ var bs []byte
+ switch v := data.(type) {
+ case *int8:
+ bs = b[:1]
+ b[0] = byte(*v)
+ case int8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case *uint8:
+ bs = b[:1]
+ b[0] = *v
+ case uint8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case *int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(*v))
+ case int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(v))
+ case *uint16:
+ bs = b[:2]
+ order.PutUint16(bs, *v)
+ case uint16:
+ bs = b[:2]
+ order.PutUint16(bs, v)
+ case *int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(*v))
+ case int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(v))
+ case *uint32:
+ bs = b[:4]
+ order.PutUint32(bs, *v)
+ case uint32:
+ bs = b[:4]
+ order.PutUint32(bs, v)
+ case *int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(*v))
+ case int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(v))
+ case *uint64:
+ bs = b[:8]
+ order.PutUint64(bs, *v)
+ case uint64:
+ bs = b[:8]
+ order.PutUint64(bs, v)
+ }
+ if bs != nil {
+ _, err := w.Write(bs)
+ return err
+ }
v := reflect.Indirect(reflect.ValueOf(data))
size := TotalSize(v)
if size < 0 {
@@ -394,3 +480,19 @@ func (e *encoder) value(v reflect.Value) {
}
}
}
+
+// intDestSize returns the size of the integer that ptrType points to,
+// or 0 if the type is not supported.
+func intDestSize(ptrType interface{}) int {
+ switch ptrType.(type) {
+ case *int8, *uint8:
+ return 1
+ case *int16, *uint16:
+ return 2
+ case *int32, *uint32:
+ return 4
+ case *int64, *uint64:
+ return 8
+ }
+ return 0
+}
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
index 7857c68d36e..b266996f635 100644
--- a/libgo/go/encoding/binary/binary_test.go
+++ b/libgo/go/encoding/binary/binary_test.go
@@ -5,6 +5,7 @@
package binary
import (
+ "io"
"os"
"bytes"
"math"
@@ -160,3 +161,75 @@ func TestWriteT(t *testing.T) {
}
}
}
+
+type byteSliceReader struct {
+ remain []byte
+}
+
+func (br *byteSliceReader) Read(p []byte) (int, os.Error) {
+ n := copy(p, br.remain)
+ br.remain = br.remain[n:]
+ return n, nil
+}
+
+func BenchmarkRead(b *testing.B) {
+ var ls Struct
+ bsr := &byteSliceReader{}
+ var r io.Reader = bsr
+
+ for i := 0; i < b.N; i++ {
+ bsr.remain = big
+ Read(r, BigEndian, &ls.Int8)
+ Read(r, BigEndian, &ls.Int16)
+ Read(r, BigEndian, &ls.Int32)
+ Read(r, BigEndian, &ls.Int64)
+ Read(r, BigEndian, &ls.Uint8)
+ Read(r, BigEndian, &ls.Uint16)
+ Read(r, BigEndian, &ls.Uint32)
+ Read(r, BigEndian, &ls.Uint64)
+ }
+
+ want := s
+ want.Float32 = 0
+ want.Float64 = 0
+ want.Complex64 = 0
+ want.Complex128 = 0
+ for i := range want.Array {
+ want.Array[i] = 0
+ }
+ if !reflect.DeepEqual(ls, want) {
+ panic("no match")
+ }
+}
+
+func BenchmarkWrite(b *testing.B) {
+ buf := new(bytes.Buffer)
+ var w io.Writer = buf
+
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Write(w, BigEndian, &s.Int8)
+ Write(w, BigEndian, &s.Int16)
+ Write(w, BigEndian, &s.Int32)
+ Write(w, BigEndian, &s.Int64)
+ Write(w, BigEndian, &s.Uint8)
+ Write(w, BigEndian, &s.Uint16)
+ Write(w, BigEndian, &s.Uint32)
+ Write(w, BigEndian, &s.Uint64)
+ Write(w, BigEndian, s.Int8)
+ Write(w, BigEndian, s.Int16)
+ Write(w, BigEndian, s.Int32)
+ Write(w, BigEndian, s.Int64)
+ Write(w, BigEndian, s.Uint8)
+ Write(w, BigEndian, s.Uint16)
+ Write(w, BigEndian, s.Uint32)
+ Write(w, BigEndian, s.Uint64)
+ }
+
+ if !bytes.Equal(buf.Bytes()[:30], big[:30]) {
+ panic("first half doesn't match")
+ }
+ if !bytes.Equal(buf.Bytes()[30:], big[:30]) {
+ panic("second half doesn't match")
+ }
+}
diff --git a/libgo/go/encoding/git85/git.go b/libgo/go/encoding/git85/git.go
index 09a45cd3c70..6bb74f46c86 100644
--- a/libgo/go/encoding/git85/git.go
+++ b/libgo/go/encoding/git85/git.go
@@ -273,5 +273,5 @@ func (d *decoder) Read(p []byte) (n int, err os.Error) {
d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf])
d.off += int64(nl + 1)
}
- panic("unreacahable")
+ panic("unreachable")
}
diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go
index 891de186107..e7ea8b0f2a6 100644
--- a/libgo/go/encoding/hex/hex.go
+++ b/libgo/go/encoding/hex/hex.go
@@ -6,6 +6,8 @@
package hex
import (
+ "bytes"
+ "io"
"os"
"strconv"
)
@@ -40,7 +42,6 @@ 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
@@ -99,3 +100,117 @@ func DecodeString(s string) ([]byte, os.Error) {
}
return dst, nil
}
+
+// Dump returns a string that contains a hex dump of the given data. The format
+// of the hex dump matches the output of `hexdump -C` on the command line.
+func Dump(data []byte) string {
+ buf := bytes.NewBuffer(nil)
+ dumper := Dumper(buf)
+ dumper.Write(data)
+ dumper.Close()
+ return string(buf.Bytes())
+}
+
+// Dumper returns a WriteCloser that writes a hex dump of all written data to
+// w. The format of the dump matches the output of `hexdump -C` on the command
+// line.
+func Dumper(w io.Writer) io.WriteCloser {
+ return &dumper{w: w}
+}
+
+type dumper struct {
+ w io.Writer
+ rightChars [18]byte
+ buf [14]byte
+ used int // number of bytes in the current line
+ n uint // number of bytes, total
+}
+
+func toChar(b byte) byte {
+ if b < 32 || b > 126 {
+ return '.'
+ }
+ return b
+}
+
+func (h *dumper) Write(data []byte) (n int, err os.Error) {
+ // Output lines look like:
+ // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
+ // ^ offset ^ extra space ^ ASCII of line.
+ for i := range data {
+ if h.used == 0 {
+ // At the beginning of a line we print the current
+ // offset in hex.
+ h.buf[0] = byte(h.n >> 24)
+ h.buf[1] = byte(h.n >> 16)
+ h.buf[2] = byte(h.n >> 8)
+ h.buf[3] = byte(h.n)
+ Encode(h.buf[4:], h.buf[:4])
+ h.buf[12] = ' '
+ h.buf[13] = ' '
+ _, err = h.w.Write(h.buf[4:])
+ }
+ Encode(h.buf[:], data[i:i+1])
+ h.buf[2] = ' '
+ l := 3
+ if h.used == 7 {
+ // There's an additional space after the 8th byte.
+ h.buf[3] = ' '
+ l = 4
+ } else if h.used == 15 {
+ // At the end of the line there's an extra space and
+ // the bar for the right column.
+ h.buf[3] = ' '
+ h.buf[4] = '|'
+ l = 5
+ }
+ _, err = h.w.Write(h.buf[:l])
+ if err != nil {
+ return
+ }
+ n++
+ h.rightChars[h.used] = toChar(data[i])
+ h.used++
+ h.n++
+ if h.used == 16 {
+ h.rightChars[16] = '|'
+ h.rightChars[17] = '\n'
+ _, err = h.w.Write(h.rightChars[:])
+ if err != nil {
+ return
+ }
+ h.used = 0
+ }
+ }
+ return
+}
+
+func (h *dumper) Close() (err os.Error) {
+ // See the comments in Write() for the details of this format.
+ if h.used == 0 {
+ return
+ }
+ h.buf[0] = ' '
+ h.buf[1] = ' '
+ h.buf[2] = ' '
+ h.buf[3] = ' '
+ h.buf[4] = '|'
+ nBytes := h.used
+ for h.used < 16 {
+ l := 3
+ if h.used == 7 {
+ l = 4
+ } else if h.used == 15 {
+ l = 5
+ }
+ _, err = h.w.Write(h.buf[:l])
+ if err != nil {
+ return
+ }
+ h.used++
+ }
+ h.rightChars[nBytes] = '|'
+ h.rightChars[nBytes+1] = '\n'
+ _, err = h.w.Write(h.rightChars[:nBytes+2])
+ return
+}
diff --git a/libgo/go/encoding/hex/hex_test.go b/libgo/go/encoding/hex/hex_test.go
index a14c9d4f4f7..8e1838e51e6 100644
--- a/libgo/go/encoding/hex/hex_test.go
+++ b/libgo/go/encoding/hex/hex_test.go
@@ -147,3 +147,46 @@ func TestDecodeString(t *testing.T) {
}
}
}
+
+func TestDumper(t *testing.T) {
+ var in [40]byte
+ for i := range in {
+ in[i] = byte(i + 30)
+ }
+
+ for stride := 1; stride < len(in); stride++ {
+ out := bytes.NewBuffer(nil)
+ dumper := Dumper(out)
+ done := 0
+ for done < len(in) {
+ todo := done + stride
+ if todo > len(in) {
+ todo = len(in)
+ }
+ dumper.Write(in[done:todo])
+ done = todo
+ }
+
+ dumper.Close()
+ if !bytes.Equal(out.Bytes(), expectedHexDump) {
+ t.Errorf("stride: %d failed. got:\n%s\nwant:\n%s", stride, out.Bytes(), expectedHexDump)
+ }
+ }
+}
+
+func TestDump(t *testing.T) {
+ var in [40]byte
+ for i := range in {
+ in[i] = byte(i + 30)
+ }
+
+ out := []byte(Dump(in[:]))
+ if !bytes.Equal(out, expectedHexDump) {
+ t.Errorf("got:\n%s\nwant:\n%s", out, expectedHexDump)
+ }
+}
+
+var expectedHexDump = []byte(`00000000 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d |.. !"#$%&'()*+,-|
+00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
+00000020 3e 3f 40 41 42 43 44 45 |>?@ABCDE|
+`)
diff --git a/libgo/go/encoding/line/line.go b/libgo/go/encoding/line/line.go
deleted file mode 100644
index 123962b1f91..00000000000
--- a/libgo/go/encoding/line/line.go
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package line implements a Reader that reads lines delimited by '\n' or
-// ' \r\n'.
-package line
-
-import (
- "io"
- "os"
-)
-
-// Reader reads lines, delimited by '\n' or \r\n', from an io.Reader.
-type Reader struct {
- buf []byte
- consumed int
- in io.Reader
- err os.Error
-}
-
-// NewReader returns a new Reader that will read successive
-// lines from the input Reader.
-func NewReader(input io.Reader, maxLineLength int) *Reader {
- return &Reader{
- buf: make([]byte, 0, maxLineLength),
- consumed: 0,
- in: input,
- }
-}
-
-// Read reads from any buffered data past the last line read, or from the underlying
-// io.Reader if the buffer is empty.
-func (l *Reader) Read(p []byte) (n int, err os.Error) {
- l.removeConsumedFromBuffer()
- if len(l.buf) > 0 {
- n = copy(p, l.buf)
- l.consumed += n
- return
- }
- return l.in.Read(p)
-}
-
-func (l *Reader) removeConsumedFromBuffer() {
- if l.consumed > 0 {
- n := copy(l.buf, l.buf[l.consumed:])
- l.buf = l.buf[:n]
- l.consumed = 0
- }
-}
-
-// 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) {
- l.removeConsumedFromBuffer()
-
- 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
- if len(l.buf) == 0 {
- return nil, false, readErr
- }
- }
- }
- panic("unreachable")
-}
diff --git a/libgo/go/encoding/line/line_test.go b/libgo/go/encoding/line/line_test.go
deleted file mode 100644
index ff3d51669b5..00000000000
--- a/libgo/go/encoding/line/line_test.go
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package line
-
-import (
- "bytes"
- "io"
- "io/ioutil"
- "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)
- }
-}
-
-func TestReadAfterLines(t *testing.T) {
- line1 := "line1"
- restData := "line2\nline 3\n"
- inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData))
- outbuf := new(bytes.Buffer)
- maxLineLength := len(line1) + len(restData)/2
- l := NewReader(inbuf, maxLineLength)
- line, isPrefix, err := l.ReadLine()
- if isPrefix || err != nil || string(line) != line1 {
- t.Errorf("bad result for first line: isPrefix=%v err=%v line=%q", isPrefix, err, string(line))
- }
- n, err := io.Copy(outbuf, l)
- if int(n) != len(restData) || err != nil {
- t.Errorf("bad result for Read: n=%d err=%v", n, err)
- }
- if outbuf.String() != restData {
- t.Errorf("bad result for Read: got %q; expected %q", outbuf.String(), restData)
- }
-}
-
-func TestReadEmptyBuffer(t *testing.T) {
- l := NewReader(bytes.NewBuffer(nil), 10)
- line, isPrefix, err := l.ReadLine()
- if err != os.EOF {
- t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
- }
-}
-
-func TestLinesAfterRead(t *testing.T) {
- l := NewReader(bytes.NewBuffer([]byte("foo")), 10)
- _, err := ioutil.ReadAll(l)
- if err != nil {
- t.Error(err)
- return
- }
-
- line, isPrefix, err := l.ReadLine()
- if err != os.EOF {
- t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
- }
-}
diff --git a/libgo/go/encoding/pem/pem.go b/libgo/go/encoding/pem/pem.go
index 44e3d0ad094..12689b57b1b 100644
--- a/libgo/go/encoding/pem/pem.go
+++ b/libgo/go/encoding/pem/pem.go
@@ -86,7 +86,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
typeLine, rest := getLine(rest)
if !bytes.HasSuffix(typeLine, pemEndOfLine) {
- goto Error
+ return decodeError(data, rest)
}
typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)]
@@ -97,7 +97,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
for {
// This loop terminates because getLine's second result is
- // always smaller than it's argument.
+ // always smaller than its argument.
if len(rest) == 0 {
return nil, data
}
@@ -118,29 +118,30 @@ func Decode(data []byte) (p *Block, rest []byte) {
i := bytes.Index(rest, pemEnd)
if i < 0 {
- goto Error
+ return decodeError(data, rest)
}
base64Data := removeWhitespace(rest[0:i])
p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
if err != nil {
- goto Error
+ return decodeError(data, rest)
}
p.Bytes = p.Bytes[0:n]
_, rest = getLine(rest[i+len(pemEnd):])
return
+}
-Error:
+func decodeError(data, rest []byte) (*Block, []byte) {
// If we get here then we have rejected a likely looking, but
// ultimately invalid PEM block. We need to start over from a new
// position. We have consumed the preamble line and will have consumed
// 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.
+ // find any valid block, no matter what bytes precede it.
//
// For example, if the input is
//
@@ -154,11 +155,11 @@ Error:
//
// we've failed to parse using the first BEGIN line
// and now will try again, using the second BEGIN line.
- p, rest = Decode(rest)
+ p, rest := Decode(rest)
if p == nil {
rest = data
}
- return
+ return p, rest
}
const pemLineLength = 64
diff --git a/libgo/go/exec/exec.go b/libgo/go/exec/exec.go
index 043f847283e..3b20f2008ca 100644
--- a/libgo/go/exec/exec.go
+++ b/libgo/go/exec/exec.go
@@ -7,198 +7,371 @@
// adjustments.
package exec
-// BUG(r): This package should be made even easier to use or merged into os.
-
import (
+ "bytes"
+ "io"
"os"
"strconv"
+ "syscall"
)
-// Arguments to Run.
-const (
- DevNull = iota
- PassThrough
- Pipe
- MergeWithStdout
-)
+// Error records the name of a binary that failed to be be executed
+// and the reason it failed.
+type Error struct {
+ Name string
+ Error os.Error
+}
-// 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.
-// Process represents the underlying operating system process.
+func (e *Error) String() string {
+ return "exec: " + strconv.Quote(e.Name) + ": " + e.Error.String()
+}
+
+// Cmd represents an external command being prepared or run.
type Cmd struct {
- Stdin *os.File
- Stdout *os.File
- Stderr *os.File
+ // Path is the path of the command to run.
+ //
+ // This is the only field that must be set to a non-zero
+ // value.
+ Path string
+
+ // Args holds command line arguments, including the command as Args[0].
+ // If the Args field is empty or nil, Run uses {Path}.
+ //
+ // In typical use, both Path and Args are set by calling Command.
+ Args []string
+
+ // Env specifies the environment of the process.
+ // If Env is nil, Run uses the current process's environment.
+ Env []string
+
+ // Dir specifies the working directory of the command.
+ // If Dir is the empty string, Run runs the command in the
+ // calling process's current directory.
+ Dir string
+
+ // Stdin specifies the process's standard input.
+ // If Stdin is nil, the process reads from DevNull.
+ Stdin io.Reader
+
+ // Stdout and Stderr specify the process's standard output and error.
+ //
+ // If either is nil, Run connects the
+ // corresponding file descriptor to /dev/null.
+ //
+ // If Stdout and Stderr are are the same writer, at most one
+ // goroutine at a time will call Write.
+ Stdout io.Writer
+ Stderr io.Writer
+
+ // SysProcAttr holds optional, operating system-specific attributes.
+ // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
+ SysProcAttr *syscall.SysProcAttr
+
+ // Process is the underlying process, once started.
Process *os.Process
+
+ err os.Error // last error (from LookPath, stdin, stdout, stderr)
+ finished bool // when Wait was called
+ childFiles []*os.File
+ closeAfterStart []io.Closer
+ closeAfterWait []io.Closer
+ goroutine []func() os.Error
+ errch chan os.Error // one send per goroutine
}
-// PathError records the name of a binary that was not
-// found on the current $PATH.
-type PathError struct {
- Name string
+// Command returns the Cmd struct to execute the named program with
+// the given arguments.
+//
+// It sets Path and Args in the returned structure and zeroes the
+// other fields.
+//
+// If name contains no path separators, Command uses LookPath to
+// resolve the path to a complete name if possible. Otherwise it uses
+// name directly.
+//
+// The returned Cmd's Args field is constructed from the command name
+// followed by the elements of arg, so arg should not include the
+// command name itself. For example, Command("echo", "hello")
+func Command(name string, arg ...string) *Cmd {
+ aname, err := LookPath(name)
+ if err != nil {
+ aname = name
+ }
+ return &Cmd{
+ Path: aname,
+ Args: append([]string{name}, arg...),
+ err: err,
+ }
}
-func (e *PathError) String() string {
- return "command " + strconv.Quote(e.Name) + " not found in $PATH"
+// interfaceEqual protects against panics from doing equality tests on
+// two interfaces with non-comparable underlying types
+func interfaceEqual(a, b interface{}) bool {
+ defer func() {
+ recover()
+ }()
+ return a == b
}
-// 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.OpenFile(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
+func (c *Cmd) envv() []string {
+ if c.Env != nil {
+ return c.Env
+ }
+ return os.Environ()
+}
+
+func (c *Cmd) argv() []string {
+ if len(c.Args) > 0 {
+ return c.Args
+ }
+ return []string{c.Path}
+}
+
+func (c *Cmd) stdin() (f *os.File, err os.Error) {
+ if c.Stdin == nil {
+ f, err = os.Open(os.DevNull)
+ c.closeAfterStart = append(c.closeAfterStart, f)
+ return
+ }
+
+ if f, ok := c.Stdin.(*os.File); ok {
+ return f, nil
+ }
+
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return
+ }
+
+ c.closeAfterStart = append(c.closeAfterStart, pr)
+ c.closeAfterWait = append(c.closeAfterWait, pw)
+ c.goroutine = append(c.goroutine, func() os.Error {
+ _, err := io.Copy(pw, c.Stdin)
+ if err1 := pw.Close(); err == nil {
+ err = err1
}
- return w, r, nil
+ return err
+ })
+ return pr, nil
+}
+
+func (c *Cmd) stdout() (f *os.File, err os.Error) {
+ return c.writerDescriptor(c.Stdout)
+}
+
+func (c *Cmd) stderr() (f *os.File, err os.Error) {
+ if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
+ return c.childFiles[1], nil
}
- return nil, nil, os.EINVAL
+ return c.writerDescriptor(c.Stderr)
}
-// Run starts the named binary running with
-// arguments argv and environment envv.
-// If the dir argument is not empty, the child changes
-// into the directory before executing the binary.
-// It returns a pointer to a new Cmd representing
-// the command or an error.
+func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) {
+ if w == nil {
+ f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
+ c.closeAfterStart = append(c.closeAfterStart, f)
+ return
+ }
+
+ if f, ok := w.(*os.File); ok {
+ return f, nil
+ }
+
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return
+ }
+
+ c.closeAfterStart = append(c.closeAfterStart, pw)
+ c.closeAfterWait = append(c.closeAfterWait, pr)
+ c.goroutine = append(c.goroutine, func() os.Error {
+ _, err := io.Copy(w, pr)
+ return err
+ })
+ return pw, nil
+}
+
+// Run starts the specified command and waits for it to complete.
//
-// The arguments 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 an argument 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) (c *Cmd, err os.Error) {
- c = new(Cmd)
- var fd [3]*os.File
-
- if fd[0], c.Stdin, err = modeToFiles(stdin, 0); err != nil {
- goto Error
- }
- if fd[1], c.Stdout, err = modeToFiles(stdout, 1); err != nil {
- goto Error
- }
- if stderr == MergeWithStdout {
- fd[2] = fd[1]
- } else if fd[2], c.Stderr, err = modeToFiles(stderr, 2); err != nil {
- goto Error
- }
-
- // Run command.
- c.Process, err = os.StartProcess(name, argv, &os.ProcAttr{Dir: dir, Files: fd[:], Env: envv})
+// The returned error is nil if the command runs, has no problems
+// copying stdin, stdout, and stderr, and exits with a zero exit
+// status.
+//
+// If the command fails to run or doesn't complete successfully, the
+// error is of type *os.Waitmsg. Other error types may be
+// returned for I/O problems.
+func (c *Cmd) Run() os.Error {
+ if err := c.Start(); err != nil {
+ return err
+ }
+ return c.Wait()
+}
+
+// Start starts the specified command but does not wait for it to complete.
+func (c *Cmd) Start() os.Error {
+ if c.err != nil {
+ return c.err
+ }
+ if c.Process != nil {
+ return os.NewError("exec: already started")
+ }
+
+ type F func(*Cmd) (*os.File, os.Error)
+ for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
+ fd, err := setupFd(c)
+ if err != nil {
+ return err
+ }
+ c.childFiles = append(c.childFiles, fd)
+ }
+
+ var err os.Error
+ c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
+ Dir: c.Dir,
+ Files: c.childFiles,
+ Env: c.envv(),
+ Sys: c.SysProcAttr,
+ })
if err != nil {
- goto Error
+ return err
}
- if fd[0] != os.Stdin {
- fd[0].Close()
+
+ for _, fd := range c.closeAfterStart {
+ fd.Close()
}
- if fd[1] != os.Stdout {
- fd[1].Close()
+
+ c.errch = make(chan os.Error, len(c.goroutine))
+ for _, fn := range c.goroutine {
+ go func(fn func() os.Error) {
+ c.errch <- fn()
+ }(fn)
}
- if fd[2] != os.Stderr && fd[2] != fd[1] {
- fd[2].Close()
+
+ return nil
+}
+
+// Wait waits for the command to exit.
+// It must have been started by Start.
+//
+// The returned error is nil if the command runs, has no problems
+// copying stdin, stdout, and stderr, and exits with a zero exit
+// status.
+//
+// If the command fails to run or doesn't complete successfully, the
+// error is of type *os.Waitmsg. Other error types may be
+// returned for I/O problems.
+func (c *Cmd) Wait() os.Error {
+ if c.Process == nil {
+ return os.NewError("exec: not started")
}
- return c, nil
+ if c.finished {
+ return os.NewError("exec: Wait was already called")
+ }
+ c.finished = true
+ msg, err := c.Process.Wait(0)
-Error:
- if fd[0] != os.Stdin && fd[0] != nil {
- fd[0].Close()
+ var copyError os.Error
+ for _ = range c.goroutine {
+ if err := <-c.errch; err != nil && copyError == nil {
+ copyError = err
+ }
}
- if fd[1] != os.Stdout && fd[1] != nil {
- fd[1].Close()
+
+ for _, fd := range c.closeAfterWait {
+ fd.Close()
}
- if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] {
- fd[2].Close()
+
+ if err != nil {
+ return err
+ } else if !msg.Exited() || msg.ExitStatus() != 0 {
+ return msg
}
- if c.Stdin != nil {
- c.Stdin.Close()
+
+ return copyError
+}
+
+// Output runs the command and returns its standard output.
+func (c *Cmd) Output() ([]byte, os.Error) {
+ if c.Stdout != nil {
+ return nil, os.NewError("exec: Stdout already set")
}
+ var b bytes.Buffer
+ c.Stdout = &b
+ err := c.Run()
+ return b.Bytes(), err
+}
+
+// CombinedOutput runs the command and returns its combined standard
+// output and standard error.
+func (c *Cmd) CombinedOutput() ([]byte, os.Error) {
if c.Stdout != nil {
- c.Stdout.Close()
+ return nil, os.NewError("exec: Stdout already set")
}
if c.Stderr != nil {
- c.Stderr.Close()
+ return nil, os.NewError("exec: Stderr already set")
}
- if c.Process != nil {
- c.Process.Release()
- }
- return nil, err
+ var b bytes.Buffer
+ c.Stdout = &b
+ c.Stderr = &b
+ err := c.Run()
+ return b.Bytes(), err
}
-// Wait waits for the running command c,
-// returning the Waitmsg returned when the process exits.
-// The options are passed to the process's Wait method.
-// Setting options to 0 waits for c to exit;
-// other options cause Wait to return for other
-// process events; see package os for details.
-func (c *Cmd) Wait(options int) (*os.Waitmsg, os.Error) {
- if c.Process == nil {
- return nil, os.ErrorString("exec: invalid use of Cmd.Wait")
+// StdinPipe returns a pipe that will be connected to the command's
+// standard input when the command starts.
+func (c *Cmd) StdinPipe() (io.WriteCloser, os.Error) {
+ if c.Stdin != nil {
+ return nil, os.NewError("exec: Stdin already set")
}
- w, err := c.Process.Wait(options)
- if w != nil && (w.Exited() || w.Signaled()) {
- c.Process.Release()
- c.Process = nil
+ if c.Process != nil {
+ return nil, os.NewError("exec: StdinPipe after process started")
+ }
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return nil, err
}
- return w, err
+ c.Stdin = pr
+ c.closeAfterStart = append(c.closeAfterStart, pr)
+ c.closeAfterWait = append(c.closeAfterWait, pw)
+ return pw, nil
}
-// Close waits for the running command c to exit,
-// if it hasn't already, and then closes the non-nil file descriptors
-// c.Stdin, c.Stdout, and c.Stderr.
-func (c *Cmd) Close() os.Error {
+// StdoutPipe returns a pipe that will be connected to the command's
+// standard output when the command starts.
+// The pipe will be closed automatically after Wait sees the command exit.
+func (c *Cmd) StdoutPipe() (io.ReadCloser, os.Error) {
+ if c.Stdout != nil {
+ return nil, os.NewError("exec: Stdout already set")
+ }
if c.Process != nil {
- // Loop on interrupt, but
- // ignore other errors -- maybe
- // caller has already waited for pid.
- _, err := c.Wait(0)
- for err == os.EINTR {
- _, err = c.Wait(0)
- }
+ return nil, os.NewError("exec: StdoutPipe after process started")
}
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return nil, err
+ }
+ c.Stdout = pw
+ c.closeAfterStart = append(c.closeAfterStart, pw)
+ c.closeAfterWait = append(c.closeAfterWait, pr)
+ return pr, nil
+}
- // Close the FDs that are still open.
- var err os.Error
- if c.Stdin != nil && c.Stdin.Fd() >= 0 {
- if err1 := c.Stdin.Close(); err1 != nil {
- err = err1
- }
+// StderrPipe returns a pipe that will be connected to the command's
+// standard error when the command starts.
+// The pipe will be closed automatically after Wait sees the command exit.
+func (c *Cmd) StderrPipe() (io.ReadCloser, os.Error) {
+ if c.Stderr != nil {
+ return nil, os.NewError("exec: Stderr already set")
}
- if c.Stdout != nil && c.Stdout.Fd() >= 0 {
- if err1 := c.Stdout.Close(); err1 != nil && err != nil {
- err = err1
- }
+ if c.Process != nil {
+ return nil, os.NewError("exec: StderrPipe after process started")
}
- if c.Stderr != nil && c.Stderr != c.Stdout && c.Stderr.Fd() >= 0 {
- if err1 := c.Stderr.Close(); err1 != nil && err != nil {
- err = err1
- }
+ pr, pw, err := os.Pipe()
+ if err != nil {
+ return nil, err
}
- return err
+ c.Stderr = pw
+ c.closeAfterStart = append(c.closeAfterStart, pw)
+ c.closeAfterWait = append(c.closeAfterWait, pr)
+ return pr, nil
}
diff --git a/libgo/go/exec/exec_test.go b/libgo/go/exec/exec_test.go
index eb8cd5fec9f..242120faab5 100644
--- a/libgo/go/exec/exec_test.go
+++ b/libgo/go/exec/exec_test.go
@@ -5,163 +5,210 @@
package exec
import (
+ "bufio"
+ "bytes"
+ "fmt"
"io"
- "io/ioutil"
"testing"
"os"
+ "strconv"
+ "strings"
)
-func run(argv []string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
- exe, err := LookPath(argv[0])
- if err != nil {
- return nil, err
- }
- return Run(exe, argv, nil, "", stdin, stdout, stderr)
+func helperCommand(s ...string) *Cmd {
+ cs := []string{"-test.run=exec.TestHelperProcess", "--"}
+ cs = append(cs, s...)
+ cmd := Command(os.Args[0], cs...)
+ cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
+ return cmd
}
-func TestRunCat(t *testing.T) {
- cmd, err := run([]string{"cat"}, Pipe, Pipe, DevNull)
+func TestEcho(t *testing.T) {
+ bs, err := helperCommand("echo", "foo bar", "baz").Output()
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)
+ t.Errorf("echo: %v", err)
}
- if err = cmd.Close(); err != nil {
- t.Fatal("close:", err)
+ if g, e := string(bs), "foo bar baz\n"; g != e {
+ t.Errorf("echo: want %q, got %q", e, g)
}
}
-func TestRunEcho(t *testing.T) {
- cmd, err := run([]string{"sh", "-c", "echo hello world"},
- DevNull, Pipe, DevNull)
+func TestCatStdin(t *testing.T) {
+ // Cat, testing stdin and stdout.
+ input := "Input string\nLine 2"
+ p := helperCommand("cat")
+ p.Stdin = strings.NewReader(input)
+ bs, err := p.Output()
if err != nil {
- t.Fatal("run:", err)
+ t.Errorf("cat: %v", 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)
+ s := string(bs)
+ if s != input {
+ t.Errorf("cat: want %q, got %q", input, s)
}
}
-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)
+func TestCatGoodAndBadFile(t *testing.T) {
+ // Testing combined output and error values.
+ bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
+ if _, ok := err.(*os.Waitmsg); !ok {
+ t.Errorf("expected Waitmsg from cat combined; got %T: %v", err, err)
}
- buf, err := ioutil.ReadAll(cmd.Stderr)
- if err != nil {
- t.Fatal("read:", err)
+ s := string(bs)
+ sp := strings.SplitN(s, "\n", 2)
+ if len(sp) != 2 {
+ t.Fatalf("expected two lines from cat; got %q", s)
}
- if string(buf) != "hello world\n" {
- t.Fatalf("read: got %q", buf)
+ errLine, body := sp[0], sp[1]
+ if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") {
+ t.Errorf("expected stderr to complain about file; got %q", errLine)
}
- if err = cmd.Close(); err != nil {
- t.Fatal("close:", err)
+ if !strings.Contains(body, "func TestHelperProcess(t *testing.T)") {
+ t.Errorf("expected test code; got %q (len %d)", body, len(body))
}
}
-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)
+func TestNoExistBinary(t *testing.T) {
+ // Can't run a non-existent binary
+ err := Command("/no-exist-binary").Run()
+ if err == nil {
+ t.Error("expected error from /no-exist-binary")
}
- if string(buf) != "hello world\n" {
- t.Fatalf("read: got %q", buf)
- }
- if err = cmd.Close(); err != nil {
- t.Fatal("close:", err)
+}
+
+func TestExitStatus(t *testing.T) {
+ // Test that exit values are returned correctly
+ err := helperCommand("exit", "42").Run()
+ if werr, ok := err.(*os.Waitmsg); ok {
+ if s, e := werr.String(), "exit status 42"; s != e {
+ t.Errorf("from exit 42 got exit %q, want %q", s, e)
+ }
+ } else {
+ t.Fatalf("expected Waitmsg from exit 42; got %T: %v", err, err)
}
}
-func TestAddEnvVar(t *testing.T) {
- err := os.Setenv("NEWVAR", "hello world")
- if err != nil {
- t.Fatal("setenv:", err)
+func TestPipes(t *testing.T) {
+ check := func(what string, err os.Error) {
+ if err != nil {
+ t.Fatalf("%s: %v", what, err)
+ }
}
- cmd, err := run([]string{"sh", "-c", "echo $NEWVAR"},
- DevNull, Pipe, DevNull)
- if err != nil {
- t.Fatal("run:", err)
+ // Cat, testing stdin and stdout.
+ c := helperCommand("pipetest")
+ stdin, err := c.StdinPipe()
+ check("StdinPipe", err)
+ stdout, err := c.StdoutPipe()
+ check("StdoutPipe", err)
+ stderr, err := c.StderrPipe()
+ check("StderrPipe", err)
+
+ outbr := bufio.NewReader(stdout)
+ errbr := bufio.NewReader(stderr)
+ line := func(what string, br *bufio.Reader) string {
+ line, _, err := br.ReadLine()
+ if err != nil {
+ t.Fatalf("%s: %v", what, err)
+ }
+ return string(line)
}
- buf, err := ioutil.ReadAll(cmd.Stdout)
- if err != nil {
- t.Fatal("read:", err)
+
+ err = c.Start()
+ check("Start", err)
+
+ _, err = stdin.Write([]byte("O:I am output\n"))
+ check("first stdin Write", err)
+ if g, e := line("first output line", outbr), "O:I am output"; g != e {
+ t.Errorf("got %q, want %q", g, e)
}
- if string(buf) != "hello world\n" {
- t.Fatalf("read: got %q", buf)
+
+ _, err = stdin.Write([]byte("E:I am error\n"))
+ check("second stdin Write", err)
+ if g, e := line("first error line", errbr), "E:I am error"; g != e {
+ t.Errorf("got %q, want %q", g, e)
}
- if err = cmd.Close(); err != nil {
- t.Fatal("close:", err)
+
+ _, err = stdin.Write([]byte("O:I am output2\n"))
+ check("third stdin Write 3", err)
+ if g, e := line("second output line", outbr), "O:I am output2"; g != e {
+ t.Errorf("got %q, want %q", g, e)
}
-}
-var tryargs = []string{
- `2`,
- `2 `,
- "2 \t",
- `2" "`,
- `2 ab `,
- `2 "ab" `,
- `2 \ `,
- `2 \\ `,
- `2 \" `,
- `2 \`,
- `2\`,
- `2"`,
- `2\"`,
- `2 "`,
- `2 \"`,
- ``,
- `2 ^ `,
- `2 \^`,
+ stdin.Close()
+ err = c.Wait()
+ check("Wait", err)
}
-func TestArgs(t *testing.T) {
- for _, a := range tryargs {
- argv := []string{
- "awk",
- `BEGIN{printf("%s|%s|%s",ARGV[1],ARGV[2],ARGV[3])}`,
- "/dev/null",
- a,
- "EOF",
- }
- exe, err := LookPath(argv[0])
- if err != nil {
- t.Fatal("run:", err)
+// TestHelperProcess isn't a real test. It's used as a helper process
+// for TestParameterRun.
+func TestHelperProcess(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ args := os.Args
+ for len(args) > 0 {
+ if args[0] == "--" {
+ args = args[1:]
+ break
}
- cmd, err := Run(exe, argv, nil, "", DevNull, Pipe, DevNull)
- if err != nil {
- t.Fatal("run:", err)
+ args = args[1:]
+ }
+ if len(args) == 0 {
+ fmt.Fprintf(os.Stderr, "No command\n")
+ os.Exit(2)
+ }
+
+ cmd, args := args[0], args[1:]
+ switch cmd {
+ case "echo":
+ iargs := []interface{}{}
+ for _, s := range args {
+ iargs = append(iargs, s)
}
- buf, err := ioutil.ReadAll(cmd.Stdout)
- if err != nil {
- t.Fatal("read:", err)
+ fmt.Println(iargs...)
+ case "cat":
+ if len(args) == 0 {
+ io.Copy(os.Stdout, os.Stdin)
+ return
}
- expect := "/dev/null|" + a + "|EOF"
- if string(buf) != expect {
- t.Errorf("read: got %q expect %q", buf, expect)
+ exit := 0
+ for _, fn := range args {
+ f, err := os.Open(fn)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+ exit = 2
+ } else {
+ defer f.Close()
+ io.Copy(os.Stdout, f)
+ }
}
- if err = cmd.Close(); err != nil {
- t.Fatal("close:", err)
+ os.Exit(exit)
+ case "pipetest":
+ bufr := bufio.NewReader(os.Stdin)
+ for {
+ line, _, err := bufr.ReadLine()
+ if err == os.EOF {
+ break
+ } else if err != nil {
+ os.Exit(1)
+ }
+ if bytes.HasPrefix(line, []byte("O:")) {
+ os.Stdout.Write(line)
+ os.Stdout.Write([]byte{'\n'})
+ } else if bytes.HasPrefix(line, []byte("E:")) {
+ os.Stderr.Write(line)
+ os.Stderr.Write([]byte{'\n'})
+ } else {
+ os.Exit(1)
+ }
}
+ case "exit":
+ n, _ := strconv.Atoi(args[0])
+ os.Exit(n)
+ default:
+ fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
+ os.Exit(2)
}
}
diff --git a/libgo/go/exec/lp_plan9.go b/libgo/go/exec/lp_plan9.go
new file mode 100644
index 00000000000..e4751a4df29
--- /dev/null
+++ b/libgo/go/exec/lp_plan9.go
@@ -0,0 +1,51 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
+var ErrNotFound = os.NewError("executable file not found in $path")
+
+func findExecutable(file string) os.Error {
+ d, err := os.Stat(file)
+ if err != nil {
+ return err
+ }
+ if d.IsRegular() && d.Permission()&0111 != 0 {
+ return nil
+ }
+ return os.EPERM
+}
+
+// LookPath searches for an executable binary named file
+// in the directories named by the path environment variable.
+// If file begins with "/", "#", "./", or "../", it is tried
+// directly and the path is not consulted.
+func LookPath(file string) (string, os.Error) {
+ // skip the path lookup for these prefixes
+ skip := []string{"/", "#", "./", "../"}
+
+ for _, p := range skip {
+ if strings.HasPrefix(file, p) {
+ err := findExecutable(file)
+ if err == nil {
+ return file, nil
+ }
+ return "", &Error{file, err}
+ }
+ }
+
+ path := os.Getenv("path")
+ for _, dir := range strings.Split(path, "\000") {
+ if err := findExecutable(dir + "/" + file); err == nil {
+ return dir + "/" + file, nil
+ }
+ }
+ return "", &Error{file, ErrNotFound}
+}
diff --git a/libgo/go/exec/lp_test.go b/libgo/go/exec/lp_test.go
index 54081771ecc..77d8e848c74 100644
--- a/libgo/go/exec/lp_test.go
+++ b/libgo/go/exec/lp_test.go
@@ -22,12 +22,12 @@ func TestLookPathNotFound(t *testing.T) {
if path != "" {
t.Fatalf("LookPath path == %q when err != nil", path)
}
- perr, ok := err.(*PathError)
+ perr, ok := err.(*Error)
if !ok {
- t.Fatal("LookPath error is not a PathError")
+ t.Fatal("LookPath error is not an exec.Error")
}
if perr.Name != name {
- t.Fatalf("want PathError name %q, got %q", name, perr.Name)
+ t.Fatalf("want Error name %q, got %q", name, perr.Name)
}
}
}
diff --git a/libgo/go/exec/lp_unix.go b/libgo/go/exec/lp_unix.go
index 44f84347b99..008fb11a81c 100644
--- a/libgo/go/exec/lp_unix.go
+++ b/libgo/go/exec/lp_unix.go
@@ -9,12 +9,18 @@ import (
"strings"
)
-func canExec(file string) bool {
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
+var ErrNotFound = os.NewError("executable file not found in $PATH")
+
+func findExecutable(file string) os.Error {
d, err := os.Stat(file)
if err != nil {
- return false
+ return err
+ }
+ if d.IsRegular() && d.Permission()&0111 != 0 {
+ return nil
}
- return d.IsRegular() && d.Permission()&0111 != 0
+ return os.EPERM
}
// LookPath searches for an executable binary named file
@@ -26,20 +32,21 @@ func LookPath(file string) (string, os.Error) {
// but that would not match all the Unix shells.
if strings.Contains(file, "/") {
- if canExec(file) {
+ err := findExecutable(file)
+ if err == nil {
return file, nil
}
- return "", &PathError{file}
+ return "", &Error{file, err}
}
pathenv := os.Getenv("PATH")
- for _, dir := range strings.Split(pathenv, ":", -1) {
+ for _, dir := range strings.Split(pathenv, ":") {
if dir == "" {
// Unix shell semantics: path element "" means "."
dir = "."
}
- if canExec(dir + "/" + file) {
+ if err := findExecutable(dir + "/" + file); err == nil {
return dir + "/" + file, nil
}
}
- return "", &PathError{file}
+ return "", &Error{file, ErrNotFound}
}
diff --git a/libgo/go/exec/lp_windows.go b/libgo/go/exec/lp_windows.go
index d357575fdbe..7581088eb09 100644
--- a/libgo/go/exec/lp_windows.go
+++ b/libgo/go/exec/lp_windows.go
@@ -9,15 +9,21 @@ import (
"strings"
)
-func chkStat(file string) bool {
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
+var ErrNotFound = os.NewError("executable file not found in %PATH%")
+
+func chkStat(file string) os.Error {
d, err := os.Stat(file)
if err != nil {
- return false
+ return err
+ }
+ if d.IsRegular() {
+ return nil
}
- return d.IsRegular()
+ return os.EPERM
}
-func canExec(file string, exts []string) (string, bool) {
+func findExecutable(file string, exts []string) (string, os.Error) {
if len(exts) == 0 {
return file, chkStat(file)
}
@@ -28,39 +34,44 @@ func canExec(file string, exts []string) (string, bool) {
}
}
for _, e := range exts {
- if f := file + e; chkStat(f) {
- return f, true
+ if f := file + e; chkStat(f) == nil {
+ return f, nil
}
}
- return ``, false
+ return ``, os.ENOENT
}
-func LookPath(file string) (string, os.Error) {
+func LookPath(file string) (f string, err os.Error) {
+ x := os.Getenv(`PATHEXT`)
+ if x == `` {
+ x = `.COM;.EXE;.BAT;.CMD`
+ }
exts := []string{}
- if x := os.Getenv(`PATHEXT`); x != `` {
- exts = strings.Split(strings.ToLower(x), `;`, -1)
- for i, e := range exts {
- if e == `` || e[0] != '.' {
- exts[i] = `.` + e
- }
+ for _, e := range strings.Split(strings.ToLower(x), `;`) {
+ if e == "" {
+ continue
+ }
+ if e[0] != '.' {
+ e = "." + e
}
+ exts = append(exts, e)
}
- if strings.Contains(file, `\`) || strings.Contains(file, `/`) {
- if f, ok := canExec(file, exts); ok {
- return f, nil
+ if strings.IndexAny(file, `:\/`) != -1 {
+ if f, err = findExecutable(file, exts); err == nil {
+ return
}
- return ``, &PathError{file}
+ return ``, &Error{file, err}
}
if pathenv := os.Getenv(`PATH`); pathenv == `` {
- if f, ok := canExec(`.\`+file, exts); ok {
- return f, nil
+ if f, err = findExecutable(`.\`+file, exts); err == nil {
+ return
}
} else {
- for _, dir := range strings.Split(pathenv, `;`, -1) {
- if f, ok := canExec(dir+`\`+file, exts); ok {
- return f, nil
+ for _, dir := range strings.Split(pathenv, `;`) {
+ if f, err = findExecutable(dir+`\`+file, exts); err == nil {
+ return
}
}
}
- return ``, &PathError{file}
+ return ``, &Error{file, ErrNotFound}
}
diff --git a/libgo/go/exp/datafmt/datafmt.go b/libgo/go/exp/datafmt/datafmt.go
index a8efdc58fe9..6d7e7644276 100644
--- a/libgo/go/exp/datafmt/datafmt.go
+++ b/libgo/go/exp/datafmt/datafmt.go
@@ -211,7 +211,6 @@ import (
"runtime"
)
-
// ----------------------------------------------------------------------------
// Format representation
@@ -228,13 +227,11 @@ import (
//
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 (
@@ -269,13 +266,11 @@ type (
}
)
-
// 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
@@ -293,7 +288,6 @@ type Environment interface {
Copy() Environment
}
-
// State represents the current formatting state.
// It is provided as argument to custom formatters.
//
@@ -309,7 +303,6 @@ type State struct {
separator expr // possibly nil
}
-
func newState(fmt Format, env Environment, errors chan os.Error) *State {
s := new(State)
s.fmt = fmt
@@ -317,12 +310,12 @@ func newState(fmt Format, env Environment, errors chan os.Error) *State {
s.errors = errors
s.linePos = token.Position{Line: 1}
- // if we have a default rule, cache it's expression for fast access
+ // if we have a default rule, cache its 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 we have a global separator rule, cache its expression for fast access
if x, found := fmt["/"]; found {
s.separator = x
}
@@ -330,17 +323,14 @@ func newState(fmt Format, env Environment, errors chan os.Error) *State {
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.
//
@@ -349,7 +339,6 @@ func (s *State) Pos() token.Position {
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.
//
@@ -371,7 +360,6 @@ func (s *State) Write(data []byte) (int, os.Error) {
return n + n3, nil
}
-
type checkpoint struct {
env Environment
hasOutput bool
@@ -379,7 +367,6 @@ type checkpoint struct {
linePos token.Position
}
-
func (s *State) save() checkpoint {
saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos}
if s.env != nil {
@@ -388,19 +375,16 @@ func (s *State) save() checkpoint {
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
@@ -440,7 +424,6 @@ func (s *State) getFormat(name string) expr {
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
@@ -594,7 +577,7 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
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
+ // the current indentation
s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()])
s.restore(mark)
@@ -653,7 +636,6 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
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
@@ -688,7 +670,6 @@ func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
return s.output.Bytes(), err
}
-
// ----------------------------------------------------------------------------
// Convenience functions
@@ -705,7 +686,6 @@ func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int,
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.
@@ -714,7 +694,6 @@ 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
diff --git a/libgo/go/exp/datafmt/datafmt_test.go b/libgo/go/exp/datafmt/datafmt_test.go
index d7c70b21dec..87d07165933 100644
--- a/libgo/go/exp/datafmt/datafmt_test.go
+++ b/libgo/go/exp/datafmt/datafmt_test.go
@@ -10,10 +10,8 @@ import (
"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 {
@@ -23,7 +21,6 @@ func parse(t *testing.T, form string, fmap FormatterMap) Format {
return f
}
-
func verify(t *testing.T, f Format, expected string, args ...interface{}) {
if f == nil {
return // allow other tests to run
@@ -36,7 +33,6 @@ func verify(t *testing.T, f Format, expected string, args ...interface{}) {
}
}
-
func formatter(s *State, value interface{}, rule_name string) bool {
switch rule_name {
case "/":
@@ -62,7 +58,6 @@ func formatter(s *State, value interface{}, rule_name string) bool {
return false
}
-
func TestCustomFormatters(t *testing.T) {
fmap0 := FormatterMap{"/": formatter}
fmap1 := FormatterMap{"int": formatter, "blank": formatter, "nil": formatter}
@@ -92,7 +87,6 @@ func TestCustomFormatters(t *testing.T) {
// TODO needs more tests
}
-
// ----------------------------------------------------------------------------
// Formatting of basic and simple composite types
@@ -109,7 +103,6 @@ func check(t *testing.T, form, expected string, args ...interface{}) {
}
}
-
func TestBasicTypes(t *testing.T) {
check(t, ``, ``)
check(t, `bool=":%v"`, `:true:false`, true, false)
@@ -144,7 +137,6 @@ func TestBasicTypes(t *testing.T) {
check(t, `float64="%g"`, fs, float64(f))
}
-
func TestArrayTypes(t *testing.T) {
var a0 [10]int
check(t, `array="array";`, `array`, a0)
@@ -159,7 +151,6 @@ func TestArrayTypes(t *testing.T) {
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)
@@ -170,7 +161,6 @@ func TestChanTypes(t *testing.T) {
// 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)
@@ -180,7 +170,6 @@ func TestFuncTypes(t *testing.T) {
// 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)
@@ -190,7 +179,6 @@ func TestMapTypes(t *testing.T) {
// check(t, `map=*`, ``, m1); // reflection support for maps incomplete
}
-
func TestPointerTypes(t *testing.T) {
var p0 *int
check(t, `ptr="ptr"`, `ptr`, p0)
@@ -203,7 +191,6 @@ func TestPointerTypes(t *testing.T) {
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)
@@ -211,13 +198,11 @@ func TestDefaultRule(t *testing.T) {
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
@@ -231,7 +216,6 @@ const F1 = `datafmt "datafmt";` +
func TestStruct1(t *testing.T) { check(t, F1, "<42>", T1{42}) }
-
// ----------------------------------------------------------------------------
// Formatting of a struct with an optional field (ptr)
@@ -256,7 +240,6 @@ func TestStruct2(t *testing.T) {
check(t, F2b, "fooempty", T2{"foo", nil})
}
-
// ----------------------------------------------------------------------------
// Formatting of a struct with a repetitive field (slice)
@@ -285,7 +268,6 @@ func TestStruct3(t *testing.T) {
check(t, F3b, "bal: 2-3-5", T3{"bal", []int{2, 3, 5}})
}
-
// ----------------------------------------------------------------------------
// Formatting of a struct with alternative field
@@ -318,7 +300,6 @@ func TestStruct4(t *testing.T) {
check(t, F4b, "<2, 3, 7>", T4{nil, []int{2, 3, 7}})
}
-
// ----------------------------------------------------------------------------
// Formatting a struct (documentation example)
@@ -338,7 +319,6 @@ func TestStructPoint(t *testing.T) {
check(t, FPoint, "---foo---{3, 0xf}", p)
}
-
// ----------------------------------------------------------------------------
// Formatting a slice (documentation example)
@@ -347,5 +327,4 @@ const FSlice = `int = "%b";` +
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
index 7dedb531a51..a2ddd389723 100644
--- a/libgo/go/exp/datafmt/parser.go
+++ b/libgo/go/exp/datafmt/parser.go
@@ -5,7 +5,6 @@
package datafmt
import (
- "container/vector"
"go/scanner"
"go/token"
"os"
@@ -28,7 +27,6 @@ type parser struct {
rules map[string]expr // RuleName -> Expression
}
-
func (p *parser) next() {
p.pos, p.tok, p.lit = p.scanner.Scan()
switch p.tok {
@@ -39,7 +37,6 @@ func (p *parser) next() {
}
}
-
func (p *parser) init(fset *token.FileSet, filename string, src []byte) {
p.ErrorVector.Reset()
p.file = fset.AddFile(filename, fset.Base(), len(src))
@@ -49,12 +46,10 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte) {
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 {
@@ -68,7 +63,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
p.error(pos, msg)
}
-
func (p *parser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
@@ -78,14 +72,12 @@ func (p *parser) expect(tok token.Token) token.Pos {
return pos
}
-
func (p *parser) parseIdentifier() string {
name := p.lit
p.expect(token.IDENT)
return name
}
-
func (p *parser) parseTypeName() (string, bool) {
pos := p.pos
name, isIdent := p.parseIdentifier(), true
@@ -102,7 +94,6 @@ func (p *parser) parseTypeName() (string, bool) {
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
@@ -126,7 +117,6 @@ func (p *parser) parseRuleName() (string, bool) {
return name, isIdent
}
-
func (p *parser) parseString() string {
s := ""
if p.tok == token.STRING {
@@ -142,7 +132,6 @@ func (p *parser) parseString() string {
return s
}
-
func (p *parser) parseLiteral() literal {
s := []byte(p.parseString())
@@ -150,14 +139,14 @@ func (p *parser) parseLiteral() literal {
// 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
+ var list []interface{}
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])
+ list = append(list, s[i0:i])
i0 = i
}
i++ // skip %; let loop skip over char after %
@@ -165,18 +154,17 @@ func (p *parser) parseLiteral() literal {
}
// the final segment may start with any character
// (it is empty iff the string is empty)
- list.Push(s[i0:])
+ list = append(list, 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)
+ lit := make(literal, len(list))
+ for i := 0; i < len(list); i++ {
+ lit[i] = list[i].([]byte)
}
return lit
}
-
func (p *parser) parseField() expr {
var fname string
switch p.tok {
@@ -204,7 +192,6 @@ func (p *parser) parseField() expr {
return &field{fname, ruleName}
}
-
func (p *parser) parseOperand() (x expr) {
switch p.tok {
case token.STRING:
@@ -242,38 +229,36 @@ func (p *parser) parseOperand() (x expr) {
return x
}
-
func (p *parser) parseSequence() expr {
- var list vector.Vector
+ var list []interface{}
for x := p.parseOperand(); x != nil; x = p.parseOperand() {
- list.Push(x)
+ list = append(list, x)
}
// no need for a sequence if list.Len() < 2
- switch list.Len() {
+ switch len(list) {
case 0:
return nil
case 1:
- return list.At(0).(expr)
+ return list[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)
+ seq := make(sequence, len(list))
+ for i := 0; i < len(list); i++ {
+ seq[i] = list[i].(expr)
}
return seq
}
-
func (p *parser) parseExpression() expr {
- var list vector.Vector
+ var list []interface{}
for {
x := p.parseSequence()
if x != nil {
- list.Push(x)
+ list = append(list, x)
}
if p.tok != token.OR {
break
@@ -282,22 +267,21 @@ func (p *parser) parseExpression() expr {
}
// no need for an alternatives if list.Len() < 2
- switch list.Len() {
+ switch len(list) {
case 0:
return nil
case 1:
- return list.At(0).(expr)
+ return list[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)
+ alt := make(alternatives, len(list))
+ for i := 0; i < len(list); i++ {
+ alt[i] = list[i].(expr)
}
return alt
}
-
func (p *parser) parseFormat() {
for p.tok != token.EOF {
pos := p.pos
@@ -343,7 +327,6 @@ func (p *parser) parseFormat() {
p.expect(token.EOF)
}
-
func remap(p *parser, name string) string {
i := strings.Index(name, ".")
if i >= 0 {
@@ -359,7 +342,6 @@ func remap(p *parser, name string) string {
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.
diff --git a/libgo/go/exp/eval/abort.go b/libgo/go/exp/eval/abort.go
deleted file mode 100644
index 22e17cec405..00000000000
--- a/libgo/go/exp/eval/abort.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index f31d9ab9bd6..00000000000
--- a/libgo/go/exp/eval/bridge.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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.Kind() {
- case reflect.Bool:
- et = BoolType
-
- case reflect.Float32:
- et = Float32Type
- case reflect.Float64:
- et = Float64Type
-
- 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.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.String:
- et = StringType
- case reflect.Array:
- et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem()))
- case reflect.Chan:
- log.Panicf("%T not implemented", t)
- case reflect.Func:
- nin := t.NumIn()
- // Variadic functions have DotDotDotType at the end
- variadic := t.IsVariadic()
- 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.Interface:
- log.Panicf("%T not implemented", t)
- case reflect.Map:
- log.Panicf("%T not implemented", t)
- case reflect.Ptr:
- et = NewPtrType(TypeFromNative(t.Elem()))
- case reflect.Slice:
- et = NewSliceType(TypeFromNative(t.Elem()))
- case reflect.Struct:
- 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.UnsafePointer:
- 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
deleted file mode 100644
index 9d2923bfca4..00000000000
--- a/libgo/go/exp/eval/compiler.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 541d3feb71d..00000000000
--- a/libgo/go/exp/eval/eval_test.go
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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) {
- delta := 1
- if testing.Short() {
- delta = 16
- }
- for i := 0; i < len(tests); i += delta {
- name := fmt.Sprintf("%s[%d]", baseName, i)
- tests[i].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
deleted file mode 100644
index e65f47617bd..00000000000
--- a/libgo/go/exp/eval/expr.go
+++ /dev/null
@@ -1,2015 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 5d0e5000032..00000000000
--- a/libgo/go/exp/eval/expr1.go
+++ /dev/null
@@ -1,1874 +0,0 @@
-// 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
deleted file mode 100644
index 0dbce431520..00000000000
--- a/libgo/go/exp/eval/expr_test.go
+++ /dev/null
@@ -1,355 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index cb1b579e42c..00000000000
--- a/libgo/go/exp/eval/func.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 66305de25f0..00000000000
--- a/libgo/go/exp/eval/scope.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index f6b7c1cda94..00000000000
--- a/libgo/go/exp/eval/stmt.go
+++ /dev/null
@@ -1,1299 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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.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.Panicf("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.List == nil {
- if hasDefault {
- a.diagAt(clause.Pos(), "switch statement contains more than one default case")
- }
- hasDefault = true
- } else {
- ncases += len(clause.List)
- }
- }
-
- // 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.List {
- 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.List != nil {
- for _ = range clause.List {
- 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
deleted file mode 100644
index a8a3e162041..00000000000
--- a/libgo/go/exp/eval/stmt_test.go
+++ /dev/null
@@ -1,343 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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", "expected identifier"),
- 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 true { 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 true { } }", "return"),
- CErr("fn1 := func() int { if true { } else { return 2 } }", "return"),
- Run("fn1 := func() int { if true { return 1 }; return 0 }"),
- Run("fn1 := func() int { if true { return 1 } else { }; return 0 }"),
- Run("fn1 := func() int { if true { return 1 } else { }; return 0 }"),
-
- // 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
deleted file mode 100644
index 8a93d8a6c27..00000000000
--- a/libgo/go/exp/eval/type.go
+++ /dev/null
@@ -1,1252 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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.ValueOf(t).Pointer()
- 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
deleted file mode 100644
index de90cf66496..00000000000
--- a/libgo/go/exp/eval/typec.go
+++ /dev/null
@@ -1,409 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index daa69189792..00000000000
--- a/libgo/go/exp/eval/value.go
+++ /dev/null
@@ -1,586 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index a5f6ac7e5e7..00000000000
--- a/libgo/go/exp/eval/world.go
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package eval 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/draw/event.go b/libgo/go/exp/gui/gui.go
index b777d912e1d..17149918605 100644
--- a/libgo/go/exp/draw/event.go
+++ b/libgo/go/exp/gui/gui.go
@@ -2,17 +2,19 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package draw
+// Package gui defines a basic graphical user interface programming model.
+package gui
import (
"image"
+ "image/draw"
"os"
)
// A Window represents a single graphics window.
type Window interface {
// Screen returns an editable Image for the window.
- Screen() Image
+ Screen() draw.Image
// FlushImage flushes changes made to Screen() back to screen.
FlushImage()
// EventChan returns a channel carrying UI events such as key presses,
diff --git a/libgo/go/exp/draw/x11/auth.go b/libgo/go/exp/gui/x11/auth.go
index d48936ac178..d48936ac178 100644
--- a/libgo/go/exp/draw/x11/auth.go
+++ b/libgo/go/exp/gui/x11/auth.go
diff --git a/libgo/go/exp/draw/x11/conn.go b/libgo/go/exp/gui/x11/conn.go
index 81c67267db6..1d237816abf 100644
--- a/libgo/go/exp/draw/x11/conn.go
+++ b/libgo/go/exp/gui/x11/conn.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package x11 implements an X11 backend for the exp/draw package.
+// Package x11 implements an X11 backend for the exp/gui package.
//
// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf.
// A summary of the wire format can be found in XCB's xproto.xml.
@@ -10,8 +10,9 @@ package x11
import (
"bufio"
- "exp/draw"
+ "exp/gui"
"image"
+ "image/draw"
"io"
"log"
"net"
@@ -43,7 +44,7 @@ type conn struct {
img *image.RGBA
eventc chan interface{}
- mouseState draw.MouseEvent
+ mouseState gui.MouseEvent
buf [256]byte // General purpose scratch buffer.
@@ -53,7 +54,7 @@ type conn struct {
}
// writeSocket runs in its own goroutine, serving both FlushImage calls
-// directly from the exp/draw client and indirectly from X expose events.
+// directly from the exp/gui client and indirectly from X expose events.
// It paints c.img to the X server via PutImage requests.
func (c *conn) writeSocket() {
defer c.c.Close()
@@ -84,25 +85,26 @@ func (c *conn) writeSocket() {
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 := c.w.Write(c.flushBuf0[: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
+ p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:]
+ for x, dx := 0, 4*b.Dx(); x < dx; {
+ nx := dx - x
+ if nx > len(c.flushBuf1) {
+ nx = len(c.flushBuf1) &^ 3
}
- for i, 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
+ for i := 0; i < nx; i += 4 {
+ // X11's order is BGRX, not RGBA.
+ c.flushBuf1[i+0] = p[x+i+2]
+ c.flushBuf1[i+1] = p[x+i+1]
+ c.flushBuf1[i+2] = p[x+i+0]
}
x += nx
- if _, err := c.w.Write(c.flushBuf1[0 : 4*nx]); err != nil {
+ if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil {
if err != os.EOF {
log.Println("x11:", err.String())
}
@@ -143,7 +145,7 @@ func (c *conn) Close() os.Error {
func (c *conn) EventChan() <-chan interface{} { return c.eventc }
-// readSocket runs in its own goroutine, reading X events and sending draw
+// readSocket runs in its own goroutine, reading X events and sending gui
// events on c's EventChan.
func (c *conn) readSocket() {
var (
@@ -153,9 +155,9 @@ func (c *conn) readSocket() {
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 := io.ReadFull(c.r, c.buf[:32]); err != nil {
if err != os.EOF {
- c.eventc <- draw.ErrEvent{err}
+ c.eventc <- gui.ErrEvent{err}
}
return
}
@@ -165,7 +167,7 @@ func (c *conn) readSocket() {
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")}
+ c.eventc <- gui.ErrEvent{os.NewError("x11: unexpected cookie")}
return
}
keysymsPerKeycode = int(c.buf[1])
@@ -176,10 +178,10 @@ func (c *conn) readSocket() {
for i := keymapLo; i <= keymapHi; i++ {
m := keymap[i]
for j := range m {
- u, err := readU32LE(c.r, c.buf[0:4])
+ u, err := readU32LE(c.r, c.buf[:4])
if err != nil {
if err != os.EOF {
- c.eventc <- draw.ErrEvent{err}
+ c.eventc <- gui.ErrEvent{err}
}
return
}
@@ -204,11 +206,11 @@ func (c *conn) readSocket() {
// 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?
+ // is that outside the scope of the gui.Window interface?
if c.buf[0] == 0x03 {
keysym = -keysym
}
- c.eventc <- draw.KeyEvent{keysym}
+ c.eventc <- gui.KeyEvent{keysym}
case 0x04, 0x05: // Button press, button release.
mask := 1 << (c.buf[1] - 1)
if c.buf[0] == 0x04 {
@@ -259,14 +261,14 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
// Parse the section before the colon.
var protocol, host, socket string
if display[0] == '/' {
- socket = display[0:colonIdx]
+ socket = display[:colonIdx]
} else {
if i := strings.LastIndex(display, "/"); i < 0 {
// The default protocol is TCP.
protocol = "tcp"
- host = display[0:colonIdx]
+ host = display[:colonIdx]
} else {
- protocol = display[0:i]
+ protocol = display[:i]
host = display[i+1 : colonIdx]
}
}
@@ -278,7 +280,7 @@ func connect(display string) (conn net.Conn, displayStr string, err os.Error) {
if i := strings.LastIndex(after, "."); i < 0 {
displayStr = after
} else {
- displayStr = after[0:i]
+ displayStr = after[:i]
}
displayInt, err := strconv.Atoi(displayStr)
if err != nil || displayInt < 0 {
@@ -310,7 +312,7 @@ func authenticate(w *bufio.Writer, displayStr string) os.Error {
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.
+ // 0x0012 and 0x0010 means the auth key and value have lengths 18 and 16.
// The final 0x0000 is padding, so that the string length is a multiple of 4.
_, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00")
if err != nil {
@@ -338,7 +340,7 @@ func authenticate(w *bufio.Writer, displayStr string) os.Error {
// 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])
+ _, err := io.ReadFull(r, b[:1])
if err != nil {
return 0, err
}
@@ -347,7 +349,7 @@ func readU8(r io.Reader, b []byte) (uint8, os.Error) {
// 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])
+ _, err := io.ReadFull(r, b[:2])
if err != nil {
return 0, err
}
@@ -356,14 +358,14 @@ func readU16LE(r io.Reader, b []byte) (uint16, os.Error) {
// 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])
+ _, err := io.ReadFull(r, b[:4])
if err != nil {
return 0, err
}
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil
}
-// setU32LE sets b[0:4] to be the little-endian representation of u.
+// setU32LE sets b[:4] to be the little-endian representation of u.
func setU32LE(b []byte, u uint32) {
b[0] = byte((u >> 0) & 0xff)
b[1] = byte((u >> 8) & 0xff)
@@ -374,7 +376,7 @@ func setU32LE(b []byte, u uint32) {
// 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])
+ _, err = io.ReadFull(r, b[:8])
if err != nil {
return
}
@@ -399,7 +401,7 @@ func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err o
return
}
// Ignore 4 bytes of padding.
- _, err = io.ReadFull(r, b[0:4])
+ _, err = io.ReadFull(r, b[:4])
if err != nil {
return
}
@@ -432,7 +434,7 @@ func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Err
}
// 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])
+ _, err = io.ReadFull(r, b[:28])
if err != nil {
return
}
@@ -461,26 +463,26 @@ func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Err
// 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])
+ _, err := io.ReadFull(c.r, c.buf[:8])
if err != nil {
return err
}
- // Byte 0:1 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
+ // Byte 0 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0).
if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 {
return os.NewError("unsupported X version")
}
// Ignore the release number.
- _, err = io.ReadFull(c.r, c.buf[0:4])
+ _, err = io.ReadFull(c.r, c.buf[:4])
if err != nil {
return err
}
// Read the resource ID base.
- resourceIdBase, err := readU32LE(c.r, c.buf[0:4])
+ resourceIdBase, err := readU32LE(c.r, c.buf[:4])
if err != nil {
return err
}
// Read the resource ID mask.
- resourceIdMask, err := readU32LE(c.r, c.buf[0:4])
+ resourceIdMask, err := readU32LE(c.r, c.buf[:4])
if err != nil {
return err
}
@@ -488,19 +490,19 @@ func (c *conn) handshake() os.Error {
return os.NewError("X resource ID mask is too small")
}
// Ignore the motion buffer size.
- _, err = io.ReadFull(c.r, c.buf[0:4])
+ _, err = io.ReadFull(c.r, c.buf[:4])
if err != nil {
return err
}
// Read the vendor length and round it up to a multiple of 4,
// for X11 protocol alignment reasons.
- vendorLen, err := readU16LE(c.r, c.buf[0:2])
+ vendorLen, err := readU16LE(c.r, c.buf[:2])
if err != nil {
return err
}
vendorLen = (vendorLen + 3) &^ 3
// Read the maximum request length.
- maxReqLen, err := readU16LE(c.r, c.buf[0:2])
+ maxReqLen, err := readU16LE(c.r, c.buf[:2])
if err != nil {
return err
}
@@ -508,27 +510,27 @@ func (c *conn) handshake() os.Error {
return os.NewError("unsupported X maximum request length")
}
// Read the roots length.
- rootsLen, err := readU8(c.r, c.buf[0:1])
+ rootsLen, err := readU8(c.r, c.buf[:1])
if err != nil {
return err
}
// Read the pixmap formats length.
- pixmapFormatsLen, err := readU8(c.r, c.buf[0:1])
+ pixmapFormatsLen, err := readU8(c.r, c.buf[:1])
if err != nil {
return err
}
- // Ignore some things that we don't care about (totalling 10 + vendorLen bytes):
+ // Ignore some things that we don't care about (totaling 10 + vendorLen bytes):
// imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1),
// minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen).
if 10+int(vendorLen) > cap(c.buf) {
return os.NewError("unsupported X vendor")
}
- _, err = io.ReadFull(c.r, c.buf[0:10+int(vendorLen)])
+ _, err = io.ReadFull(c.r, c.buf[:10+int(vendorLen)])
if err != nil {
return err
}
// Check that we have an agreeable pixmap format.
- agree, err := checkPixmapFormats(c.r, c.buf[0:8], int(pixmapFormatsLen))
+ agree, err := checkPixmapFormats(c.r, c.buf[:8], int(pixmapFormatsLen))
if err != nil {
return err
}
@@ -536,7 +538,7 @@ func (c *conn) handshake() os.Error {
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))
+ root, visual, err := checkScreens(c.r, c.buf[:24], int(rootsLen))
if err != nil {
return err
}
@@ -551,7 +553,7 @@ func (c *conn) handshake() os.Error {
}
// NewWindow calls NewWindowDisplay with $DISPLAY.
-func NewWindow() (draw.Window, os.Error) {
+func NewWindow() (gui.Window, os.Error) {
display := os.Getenv("DISPLAY")
if len(display) == 0 {
return nil, os.NewError("$DISPLAY not set")
@@ -559,10 +561,10 @@ func NewWindow() (draw.Window, os.Error) {
return NewWindowDisplay(display)
}
-// NewWindowDisplay returns a new draw.Window, backed by a newly created and
+// NewWindowDisplay returns a new gui.Window, backed by a newly created and
// mapped X11 window. The X server to connect to is specified by the display
// string, such as ":1".
-func NewWindowDisplay(display string) (draw.Window, os.Error) {
+func NewWindowDisplay(display string) (gui.Window, os.Error) {
socket, displayStr, err := connect(display)
if err != nil {
return nil, err
@@ -607,7 +609,7 @@ func NewWindowDisplay(display string) (draw.Window, os.Error) {
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])
+ _, err = c.w.Write(c.buf[:80])
if err != nil {
return nil, err
}
diff --git a/libgo/go/exp/norm/composition.go b/libgo/go/exp/norm/composition.go
new file mode 100644
index 00000000000..b2d2abaf63b
--- /dev/null
+++ b/libgo/go/exp/norm/composition.go
@@ -0,0 +1,344 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+import "utf8"
+
+const (
+ maxCombiningChars = 30 + 2 // +2 to hold CGJ and Hangul overflow.
+ maxBackRunes = maxCombiningChars - 1
+ maxNFCExpansion = 3 // NFC(0x1D160)
+ maxNFKCExpansion = 18 // NFKC(0xFDFA)
+
+ maxRuneSizeInDecomp = 4
+ // Need to multiply by 2 as we don't reuse byte buffer space for recombining.
+ maxByteBufferSize = 2 * maxRuneSizeInDecomp * maxCombiningChars // 256
+)
+
+// reorderBuffer is used to normalize a single segment. Characters inserted with
+// insert() are decomposed and reordered based on CCC. The compose() method can
+// be used to recombine characters. Note that the byte buffer does not hold
+// the UTF-8 characters in order. Only the rune array is maintained in sorted
+// order. flush() writes the resulting segment to a byte array.
+type reorderBuffer struct {
+ rune [maxCombiningChars]runeInfo // Per character info.
+ byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos.
+ nrune int // Number of runeInfos.
+ nbyte uint8 // Number or bytes.
+ f formInfo
+}
+
+// reset discards all characters from the buffer.
+func (rb *reorderBuffer) reset() {
+ rb.nrune = 0
+ rb.nbyte = 0
+}
+
+// flush appends the normalized segment to out and resets rb.
+func (rb *reorderBuffer) flush(out []byte) []byte {
+ for i := 0; i < rb.nrune; i++ {
+ start := rb.rune[i].pos
+ end := start + rb.rune[i].size
+ out = append(out, rb.byte[start:end]...)
+ }
+ rb.reset()
+ return out
+}
+
+// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class.
+// It returns false if the buffer is not large enough to hold the rune.
+// It is used internally by insert.
+func (rb *reorderBuffer) insertOrdered(info runeInfo) bool {
+ n := rb.nrune
+ if n >= maxCombiningChars {
+ return false
+ }
+ b := rb.rune[:]
+ cc := info.ccc
+ if cc > 0 {
+ // Find insertion position + move elements to make room.
+ for ; n > 0; n-- {
+ if b[n-1].ccc <= cc {
+ break
+ }
+ b[n] = b[n-1]
+ }
+ }
+ rb.nrune += 1
+ pos := uint8(rb.nbyte)
+ rb.nbyte += info.size
+ info.pos = pos
+ b[n] = info
+ return true
+}
+
+// insert inserts the given rune in the buffer ordered by CCC.
+// It returns true if the buffer was large enough to hold the decomposed rune.
+func (rb *reorderBuffer) insert(src []byte, info runeInfo) bool {
+ if info.size == 3 && isHangul(src) {
+ rune, _ := utf8.DecodeRune(src)
+ return rb.decomposeHangul(uint32(rune))
+ }
+ pos := rb.nbyte
+ if info.flags.hasDecomposition() {
+ dcomp := rb.f.decompose(src)
+ for i := 0; i < len(dcomp); i += int(info.size) {
+ info = rb.f.info(dcomp[i:])
+ if !rb.insertOrdered(info) {
+ return false
+ }
+ }
+ copy(rb.byte[pos:], dcomp)
+ } else {
+ if !rb.insertOrdered(info) {
+ return false
+ }
+ copy(rb.byte[pos:], src[:info.size])
+ }
+ return true
+}
+
+// insertString inserts the given rune in the buffer ordered by CCC.
+// It returns true if the buffer was large enough to hold the decomposed rune.
+func (rb *reorderBuffer) insertString(src string, info runeInfo) bool {
+ if info.size == 3 && isHangulString(src) {
+ rune, _ := utf8.DecodeRuneInString(src)
+ return rb.decomposeHangul(uint32(rune))
+ }
+ pos := rb.nbyte
+ dcomp := rb.f.decomposeString(src)
+ dn := len(dcomp)
+ if dn != 0 {
+ for i := 0; i < dn; i += int(info.size) {
+ info = rb.f.info(dcomp[i:])
+ if !rb.insertOrdered(info) {
+ return false
+ }
+ }
+ copy(rb.byte[pos:], dcomp)
+ } else {
+ if !rb.insertOrdered(info) {
+ return false
+ }
+ copy(rb.byte[pos:], src[:info.size])
+ }
+ return true
+}
+
+// appendRune inserts a rune at the end of the buffer. It is used for Hangul.
+func (rb *reorderBuffer) appendRune(rune uint32) {
+ bn := rb.nbyte
+ sz := utf8.EncodeRune(rb.byte[bn:], int(rune))
+ rb.nbyte += uint8(sz)
+ rb.rune[rb.nrune] = runeInfo{bn, uint8(sz), 0, 0}
+ rb.nrune++
+}
+
+// assignRune sets a rune at position pos. It is used for Hangul and recomposition.
+func (rb *reorderBuffer) assignRune(pos int, rune uint32) {
+ bn := rb.nbyte
+ sz := utf8.EncodeRune(rb.byte[bn:], int(rune))
+ rb.rune[pos] = runeInfo{bn, uint8(sz), 0, 0}
+ rb.nbyte += uint8(sz)
+}
+
+// runeAt returns the rune at position n. It is used for Hangul and recomposition.
+func (rb *reorderBuffer) runeAt(n int) uint32 {
+ inf := rb.rune[n]
+ rune, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size])
+ return uint32(rune)
+}
+
+// bytesAt returns the UTF-8 encoding of the rune at position n.
+// It is used for Hangul and recomposition.
+func (rb *reorderBuffer) bytesAt(n int) []byte {
+ inf := rb.rune[n]
+ return rb.byte[inf.pos : int(inf.pos)+int(inf.size)]
+}
+
+// For Hangul we combine algorithmically, instead of using tables.
+const (
+ hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80
+ hangulBase0 = 0xEA
+ hangulBase1 = 0xB0
+ hangulBase2 = 0x80
+
+ hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4
+ hangulEnd0 = 0xED
+ hangulEnd1 = 0x9E
+ hangulEnd2 = 0xA4
+
+ jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00
+ jamoLBase0 = 0xE1
+ jamoLBase1 = 0x84
+ jamoLEnd = 0x1113
+ jamoVBase = 0x1161
+ jamoVEnd = 0x1176
+ jamoTBase = 0x11A7
+ jamoTEnd = 0x11C3
+
+ jamoTCount = 28
+ jamoVCount = 21
+ jamoVTCount = 21 * 28
+ jamoLVTCount = 19 * 21 * 28
+)
+
+// Caller must verify that len(b) >= 3.
+func isHangul(b []byte) bool {
+ b0 := b[0]
+ if b0 < hangulBase0 {
+ return false
+ }
+ b1 := b[1]
+ switch {
+ case b0 == hangulBase0:
+ return b1 >= hangulBase1
+ case b0 < hangulEnd0:
+ return true
+ case b0 > hangulEnd0:
+ return false
+ case b1 < hangulEnd1:
+ return true
+ }
+ return b1 == hangulEnd1 && b[2] < hangulEnd2
+}
+
+// Caller must verify that len(b) >= 3.
+func isHangulString(b string) bool {
+ b0 := b[0]
+ if b0 < hangulBase0 {
+ return false
+ }
+ b1 := b[1]
+ switch {
+ case b0 == hangulBase0:
+ return b1 >= hangulBase1
+ case b0 < hangulEnd0:
+ return true
+ case b0 > hangulEnd0:
+ return false
+ case b1 < hangulEnd1:
+ return true
+ }
+ return b1 == hangulEnd1 && b[2] < hangulEnd2
+}
+
+// Caller must ensure len(b) >= 2.
+func isJamoVT(b []byte) bool {
+ // True if (rune & 0xff00) == jamoLBase
+ return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1
+}
+
+func isHangulWithoutJamoT(b []byte) bool {
+ c, _ := utf8.DecodeRune(b)
+ c -= hangulBase
+ return c < jamoLVTCount && c%jamoTCount == 0
+}
+
+// decomposeHangul algorithmically decomposes a Hangul rune into
+// its Jamo components.
+// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
+func (rb *reorderBuffer) decomposeHangul(rune uint32) bool {
+ b := rb.rune[:]
+ n := rb.nrune
+ if n+3 > len(b) {
+ return false
+ }
+ rune -= hangulBase
+ x := rune % jamoTCount
+ rune /= jamoTCount
+ rb.appendRune(jamoLBase + rune/jamoVCount)
+ rb.appendRune(jamoVBase + rune%jamoVCount)
+ if x != 0 {
+ rb.appendRune(jamoTBase + x)
+ }
+ return true
+}
+
+// combineHangul algorithmically combines Jamo character components into Hangul.
+// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
+func (rb *reorderBuffer) combineHangul() {
+ k := 1
+ b := rb.rune[:]
+ bn := rb.nrune
+ for s, i := 0, 1; i < bn; i++ {
+ cccB := b[k-1].ccc
+ cccC := b[i].ccc
+ if cccB == 0 {
+ s = k - 1
+ }
+ if s != k-1 && cccB >= cccC {
+ // b[i] is blocked by greater-equal cccX below it
+ b[k] = b[i]
+ k++
+ } else {
+ l := rb.runeAt(s) // also used to compare to hangulBase
+ v := rb.runeAt(i) // also used to compare to jamoT
+ switch {
+ case jamoLBase <= l && l < jamoLEnd &&
+ jamoVBase <= v && v < jamoVEnd:
+ // 11xx plus 116x to LV
+ rb.assignRune(s, hangulBase+
+ (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount)
+ case hangulBase <= l && l < hangulEnd &&
+ jamoTBase < v && v < jamoTEnd &&
+ ((l-hangulBase)%jamoTCount) == 0:
+ // ACxx plus 11Ax to LVT
+ rb.assignRune(s, l+v-jamoTBase)
+ default:
+ b[k] = b[i]
+ k++
+ }
+ }
+ }
+ rb.nrune = k
+}
+
+// compose recombines the runes in the buffer.
+// It should only be used to recompose a single segment, as it will not
+// handle alternations between Hangul and non-Hangul characters correctly.
+func (rb *reorderBuffer) compose() {
+ // UAX #15, section X5 , including Corrigendum #5
+ // "In any character sequence beginning with starter S, a character C is
+ // blocked from S if and only if there is some character B between S
+ // and C, and either B is a starter or it has the same or higher
+ // combining class as C."
+ k := 1
+ b := rb.rune[:]
+ bn := rb.nrune
+ for s, i := 0, 1; i < bn; i++ {
+ if isJamoVT(rb.bytesAt(i)) {
+ // Redo from start in Hangul mode. Necessary to support
+ // U+320E..U+321E in NFKC mode.
+ rb.combineHangul()
+ return
+ }
+ ii := b[i]
+ // We can only use combineForward as a filter if we later
+ // get the info for the combined character. This is more
+ // expensive than using the filter. Using combinesBackward()
+ // is safe.
+ if ii.flags.combinesBackward() {
+ cccB := b[k-1].ccc
+ cccC := ii.ccc
+ blocked := false // b[i] blocked by starter or greater or equal CCC?
+ if cccB == 0 {
+ s = k - 1
+ } else {
+ blocked = s != k-1 && cccB >= cccC
+ }
+ if !blocked {
+ combined := combine(rb.runeAt(s), rb.runeAt(i))
+ if combined != 0 {
+ rb.assignRune(s, combined)
+ continue
+ }
+ }
+ }
+ b[k] = b[i]
+ k++
+ }
+ rb.nrune = k
+}
diff --git a/libgo/go/exp/norm/composition_test.go b/libgo/go/exp/norm/composition_test.go
new file mode 100644
index 00000000000..195a0c1e8e9
--- /dev/null
+++ b/libgo/go/exp/norm/composition_test.go
@@ -0,0 +1,138 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+import "testing"
+
+// TestCase is used for most tests.
+type TestCase struct {
+ in []int
+ out []int
+}
+
+type insertFunc func(rb *reorderBuffer, rune int) bool
+
+func insert(rb *reorderBuffer, rune int) bool {
+ b := []byte(string(rune))
+ return rb.insert(b, rb.f.info(b))
+}
+
+func insertString(rb *reorderBuffer, rune int) bool {
+ s := string(rune)
+ return rb.insertString(s, rb.f.infoString(s))
+}
+
+func runTests(t *testing.T, name string, rb *reorderBuffer, f insertFunc, tests []TestCase) {
+ for i, test := range tests {
+ rb.reset()
+ for j, rune := range test.in {
+ b := []byte(string(rune))
+ if !rb.insert(b, rb.f.info(b)) {
+ t.Errorf("%s:%d: insert failed for rune %d", name, i, j)
+ }
+ }
+ if rb.f.composing {
+ rb.compose()
+ }
+ if rb.nrune != len(test.out) {
+ t.Errorf("%s:%d: length = %d; want %d", name, i, rb.nrune, len(test.out))
+ continue
+ }
+ for j, want := range test.out {
+ found := int(rb.runeAt(j))
+ if found != want {
+ t.Errorf("%s:%d: runeAt(%d) = %U; want %U", name, i, j, found, want)
+ }
+ }
+ }
+}
+
+func TestFlush(t *testing.T) {
+ rb := &reorderBuffer{f: *formTable[NFC]}
+ out := make([]byte, 0)
+
+ out = rb.flush(out)
+ if len(out) != 0 {
+ t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", len(out))
+ }
+
+ for _, r := range []int("world!") {
+ insert(rb, r)
+ }
+
+ out = []byte("Hello ")
+ out = rb.flush(out)
+ want := "Hello world!"
+ if string(out) != want {
+ t.Errorf(`output after flush was "%s"; want "%s"`, string(out), want)
+ }
+ if rb.nrune != 0 {
+ t.Errorf("flush: non-null size of info buffer (rb.nrune == %d)", rb.nrune)
+ }
+ if rb.nbyte != 0 {
+ t.Errorf("flush: non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte)
+ }
+}
+
+var insertTests = []TestCase{
+ {[]int{'a'}, []int{'a'}},
+ {[]int{0x300}, []int{0x300}},
+ {[]int{0x300, 0x316}, []int{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220
+ {[]int{0x316, 0x300}, []int{0x316, 0x300}},
+ {[]int{0x41, 0x316, 0x300}, []int{0x41, 0x316, 0x300}},
+ {[]int{0x41, 0x300, 0x316}, []int{0x41, 0x316, 0x300}},
+ {[]int{0x300, 0x316, 0x41}, []int{0x316, 0x300, 0x41}},
+ {[]int{0x41, 0x300, 0x40, 0x316}, []int{0x41, 0x300, 0x40, 0x316}},
+}
+
+func TestInsert(t *testing.T) {
+ rb := &reorderBuffer{f: *formTable[NFD]}
+ runTests(t, "TestInsert", rb, insert, insertTests)
+}
+
+func TestInsertString(t *testing.T) {
+ rb := &reorderBuffer{f: *formTable[NFD]}
+ runTests(t, "TestInsertString", rb, insertString, insertTests)
+}
+
+var decompositionNFDTest = []TestCase{
+ {[]int{0xC0}, []int{0x41, 0x300}},
+ {[]int{0xAC00}, []int{0x1100, 0x1161}},
+ {[]int{0x01C4}, []int{0x01C4}},
+ {[]int{0x320E}, []int{0x320E}},
+ {[]int("음ẻ과"), []int{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}},
+}
+
+var decompositionNFKDTest = []TestCase{
+ {[]int{0xC0}, []int{0x41, 0x300}},
+ {[]int{0xAC00}, []int{0x1100, 0x1161}},
+ {[]int{0x01C4}, []int{0x44, 0x5A, 0x030C}},
+ {[]int{0x320E}, []int{0x28, 0x1100, 0x1161, 0x29}},
+}
+
+func TestDecomposition(t *testing.T) {
+ rb := &reorderBuffer{}
+ rb.f = *formTable[NFD]
+ runTests(t, "TestDecompositionNFD", rb, insert, decompositionNFDTest)
+ rb.f = *formTable[NFKD]
+ runTests(t, "TestDecompositionNFKD", rb, insert, decompositionNFKDTest)
+}
+
+var compositionTest = []TestCase{
+ {[]int{0x41, 0x300}, []int{0xC0}},
+ {[]int{0x41, 0x316}, []int{0x41, 0x316}},
+ {[]int{0x41, 0x300, 0x35D}, []int{0xC0, 0x35D}},
+ {[]int{0x41, 0x316, 0x300}, []int{0xC0, 0x316}},
+ // blocking starter
+ {[]int{0x41, 0x316, 0x40, 0x300}, []int{0x41, 0x316, 0x40, 0x300}},
+ {[]int{0x1100, 0x1161}, []int{0xAC00}},
+ // parenthesized Hangul, alternate between ASCII and Hangul.
+ {[]int{0x28, 0x1100, 0x1161, 0x29}, []int{0x28, 0xAC00, 0x29}},
+}
+
+func TestComposition(t *testing.T) {
+ rb := &reorderBuffer{f: *formTable[NFC]}
+ runTests(t, "TestComposition", rb, insert, compositionTest)
+}
diff --git a/libgo/go/exp/norm/forminfo.go b/libgo/go/exp/norm/forminfo.go
new file mode 100644
index 00000000000..ee3edb8ea7d
--- /dev/null
+++ b/libgo/go/exp/norm/forminfo.go
@@ -0,0 +1,188 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+// This file contains Form-specific logic and wrappers for data in tables.go.
+
+type runeInfo struct {
+ pos uint8 // start position in reorderBuffer; used in composition.go
+ size uint8 // length of UTF-8 encoding of this rune
+ ccc uint8 // canonical combining class
+ flags qcInfo // quick check flags
+}
+
+// functions dispatchable per form
+type boundaryFunc func(f *formInfo, info runeInfo) bool
+type lookupFunc func(b []byte) runeInfo
+type lookupFuncString func(s string) runeInfo
+type decompFunc func(b []byte) []byte
+type decompFuncString func(s string) []byte
+
+// formInfo holds Form-specific functions and tables.
+type formInfo struct {
+ form Form
+
+ composing, compatibility bool // form type
+
+ decompose decompFunc
+ decomposeString decompFuncString
+ info lookupFunc
+ infoString lookupFuncString
+ boundaryBefore boundaryFunc
+ boundaryAfter boundaryFunc
+}
+
+var formTable []*formInfo
+
+func init() {
+ formTable = make([]*formInfo, 4)
+
+ for i := range formTable {
+ f := &formInfo{}
+ formTable[i] = f
+ f.form = Form(i)
+ if Form(i) == NFKD || Form(i) == NFKC {
+ f.compatibility = true
+ f.decompose = decomposeNFKC
+ f.decomposeString = decomposeStringNFKC
+ f.info = lookupInfoNFKC
+ f.infoString = lookupInfoStringNFKC
+ } else {
+ f.decompose = decomposeNFC
+ f.decomposeString = decomposeStringNFC
+ f.info = lookupInfoNFC
+ f.infoString = lookupInfoStringNFC
+ }
+ if Form(i) == NFC || Form(i) == NFKC {
+ f.composing = true
+ f.boundaryBefore = compBoundaryBefore
+ f.boundaryAfter = compBoundaryAfter
+ } else {
+ f.boundaryBefore = decompBoundary
+ f.boundaryAfter = decompBoundary
+ }
+ }
+}
+
+func decompBoundary(f *formInfo, info runeInfo) bool {
+ if info.ccc == 0 && info.flags.isYesD() { // Implies isHangul(b) == true
+ return true
+ }
+ // We assume that the CCC of the first character in a decomposition
+ // is always non-zero if different from info.ccc and that we can return
+ // false at this point. This is verified by maketables.
+ return false
+}
+
+func compBoundaryBefore(f *formInfo, info runeInfo) bool {
+ if info.ccc == 0 && info.flags.isYesC() {
+ return true
+ }
+ // We assume that the CCC of the first character in a decomposition
+ // is always non-zero if different from info.ccc and that we can return
+ // false at this point. This is verified by maketables.
+ return false
+}
+
+func compBoundaryAfter(f *formInfo, info runeInfo) bool {
+ // This misses values where the last char in a decomposition is a
+ // boundary such as Hangul with JamoT.
+ // TODO(mpvl): verify this does not lead to segments that do
+ // not fit in the reorderBuffer.
+ return info.flags.isInert()
+}
+
+// We pack quick check data in 4 bits:
+// 0: NFD_QC Yes (0) or No (1). No also means there is a decomposition.
+// 1..2: NFC_QC Yes(00), No (01), or Maybe (11)
+// 3: Combines forward (0 == false, 1 == true)
+//
+// When all 4 bits are zero, the character is inert, meaning it is never
+// influenced by normalization.
+//
+// We pack the bits for both NFC/D and NFKC/D in one byte.
+type qcInfo uint8
+
+func (i qcInfo) isYesC() bool { return i&0x2 == 0 }
+func (i qcInfo) isNoC() bool { return i&0x6 == 0x2 }
+func (i qcInfo) isMaybe() bool { return i&0x4 != 0 }
+func (i qcInfo) isYesD() bool { return i&0x1 == 0 }
+func (i qcInfo) isNoD() bool { return i&0x1 != 0 }
+func (i qcInfo) isInert() bool { return i&0xf == 0 }
+
+func (i qcInfo) combinesForward() bool { return i&0x8 != 0 }
+func (i qcInfo) combinesBackward() bool { return i&0x4 != 0 } // == isMaybe
+func (i qcInfo) hasDecomposition() bool { return i&0x1 != 0 } // == isNoD
+
+// Wrappers for tables.go
+
+// The 16-bit value of the decompostion tries is an index into a byte
+// array of UTF-8 decomposition sequences. The first byte is the number
+// of bytes in the decomposition (excluding this length byte). The actual
+// sequence starts at the offset+1.
+func decomposeNFC(b []byte) []byte {
+ p := nfcDecompTrie.lookupUnsafe(b)
+ n := decomps[p]
+ p++
+ return decomps[p : p+uint16(n)]
+}
+
+func decomposeNFKC(b []byte) []byte {
+ p := nfkcDecompTrie.lookupUnsafe(b)
+ n := decomps[p]
+ p++
+ return decomps[p : p+uint16(n)]
+}
+
+func decomposeStringNFC(s string) []byte {
+ p := nfcDecompTrie.lookupStringUnsafe(s)
+ n := decomps[p]
+ p++
+ return decomps[p : p+uint16(n)]
+}
+
+func decomposeStringNFKC(s string) []byte {
+ p := nfkcDecompTrie.lookupStringUnsafe(s)
+ n := decomps[p]
+ p++
+ return decomps[p : p+uint16(n)]
+}
+
+// Recomposition
+// We use 32-bit keys instead of 64-bit for the two codepoint keys.
+// This clips off the bits of three entries, but we know this will not
+// result in a collision. In the unlikely event that changes to
+// UnicodeData.txt introduce collisions, the compiler will catch it.
+// Note that the recomposition map for NFC and NFKC are identical.
+
+// combine returns the combined rune or 0 if it doesn't exist.
+func combine(a, b uint32) uint32 {
+ key := uint32(uint16(a))<<16 + uint32(uint16(b))
+ return recompMap[key]
+}
+
+// The 16-bit character info has the following bit layout:
+// 0..7 CCC value.
+// 8..11 qcInfo for NFC/NFD
+// 12..15 qcInfo for NFKC/NFKD
+func lookupInfoNFC(b []byte) runeInfo {
+ v, sz := charInfoTrie.lookup(b)
+ return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 8)}
+}
+
+func lookupInfoStringNFC(s string) runeInfo {
+ v, sz := charInfoTrie.lookupString(s)
+ return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 8)}
+}
+
+func lookupInfoNFKC(b []byte) runeInfo {
+ v, sz := charInfoTrie.lookup(b)
+ return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 12)}
+}
+
+func lookupInfoStringNFKC(s string) runeInfo {
+ v, sz := charInfoTrie.lookupString(s)
+ return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 12)}
+}
diff --git a/libgo/go/exp/norm/maketables.go b/libgo/go/exp/norm/maketables.go
new file mode 100644
index 00000000000..e3e5700a64e
--- /dev/null
+++ b/libgo/go/exp/norm/maketables.go
@@ -0,0 +1,855 @@
+// 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.
+
+// Normalization table generator.
+// Data read from the web.
+
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "flag"
+ "fmt"
+ "http"
+ "io"
+ "log"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+func main() {
+ flag.Parse()
+ loadUnicodeData()
+ loadCompositionExclusions()
+ completeCharFields(FCanonical)
+ completeCharFields(FCompatibility)
+ verifyComputed()
+ printChars()
+ makeTables()
+ testDerived()
+}
+
+var url = flag.String("url",
+ "http://www.unicode.org/Public/6.0.0/ucd/",
+ "URL of Unicode database directory")
+var tablelist = flag.String("tables",
+ "all",
+ "comma-separated list of which tables to generate; "+
+ "can be 'decomp', 'recomp', 'info' and 'all'")
+var test = flag.Bool("test",
+ false,
+ "test existing tables; can be used to compare web data with package data")
+var verbose = flag.Bool("verbose",
+ false,
+ "write data to stdout as it is parsed")
+var localFiles = flag.Bool("local",
+ false,
+ "data files have been copied to the current directory; for debugging only")
+
+var logger = log.New(os.Stderr, "", log.Lshortfile)
+
+// UnicodeData.txt has form:
+// 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
+// 007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
+// See http://unicode.org/reports/tr44/ for full explanation
+// The fields:
+const (
+ FCodePoint = iota
+ FName
+ FGeneralCategory
+ FCanonicalCombiningClass
+ FBidiClass
+ FDecompMapping
+ FDecimalValue
+ FDigitValue
+ FNumericValue
+ FBidiMirrored
+ FUnicode1Name
+ FISOComment
+ FSimpleUppercaseMapping
+ FSimpleLowercaseMapping
+ FSimpleTitlecaseMapping
+ NumField
+
+ MaxChar = 0x10FFFF // anything above this shouldn't exist
+)
+
+// Quick Check properties of runes allow us to quickly
+// determine whether a rune may occur in a normal form.
+// For a given normal form, a rune may be guaranteed to occur
+// verbatim (QC=Yes), may or may not combine with another
+// rune (QC=Maybe), or may not occur (QC=No).
+type QCResult int
+
+const (
+ QCUnknown QCResult = iota
+ QCYes
+ QCNo
+ QCMaybe
+)
+
+func (r QCResult) String() string {
+ switch r {
+ case QCYes:
+ return "Yes"
+ case QCNo:
+ return "No"
+ case QCMaybe:
+ return "Maybe"
+ }
+ return "***UNKNOWN***"
+}
+
+const (
+ FCanonical = iota // NFC or NFD
+ FCompatibility // NFKC or NFKD
+ FNumberOfFormTypes
+)
+
+const (
+ MComposed = iota // NFC or NFKC
+ MDecomposed // NFD or NFKD
+ MNumberOfModes
+)
+
+// This contains only the properties we're interested in.
+type Char struct {
+ name string
+ codePoint int // if zero, this index is not a valid code point.
+ ccc uint8 // canonical combining class
+ excludeInComp bool // from CompositionExclusions.txt
+ compatDecomp bool // it has a compatibility expansion
+
+ forms [FNumberOfFormTypes]FormInfo // For FCanonical and FCompatibility
+
+ state State
+}
+
+var chars = make([]Char, MaxChar+1)
+
+func (c Char) String() string {
+ buf := new(bytes.Buffer)
+
+ fmt.Fprintf(buf, "%U [%s]:\n", c.codePoint, c.name)
+ fmt.Fprintf(buf, " ccc: %v\n", c.ccc)
+ fmt.Fprintf(buf, " excludeInComp: %v\n", c.excludeInComp)
+ fmt.Fprintf(buf, " compatDecomp: %v\n", c.compatDecomp)
+ fmt.Fprintf(buf, " state: %v\n", c.state)
+ fmt.Fprintf(buf, " NFC:\n")
+ fmt.Fprint(buf, c.forms[FCanonical])
+ fmt.Fprintf(buf, " NFKC:\n")
+ fmt.Fprint(buf, c.forms[FCompatibility])
+
+ return buf.String()
+}
+
+// In UnicodeData.txt, some ranges are marked like this:
+// 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
+// 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+// parseCharacter keeps a state variable indicating the weirdness.
+type State int
+
+const (
+ SNormal State = iota // known to be zero for the type
+ SFirst
+ SLast
+ SMissing
+)
+
+var lastChar int = 0
+
+func (c Char) isValid() bool {
+ return c.codePoint != 0 && c.state != SMissing
+}
+
+type FormInfo struct {
+ quickCheck [MNumberOfModes]QCResult // index: MComposed or MDecomposed
+ verified [MNumberOfModes]bool // index: MComposed or MDecomposed
+
+ combinesForward bool // May combine with rune on the right
+ combinesBackward bool // May combine with rune on the left
+ isOneWay bool // Never appears in result
+ inDecomp bool // Some decompositions result in this char.
+ decomp Decomposition
+ expandedDecomp Decomposition
+}
+
+func (f FormInfo) String() string {
+ buf := bytes.NewBuffer(make([]byte, 0))
+
+ fmt.Fprintf(buf, " quickCheck[C]: %v\n", f.quickCheck[MComposed])
+ fmt.Fprintf(buf, " quickCheck[D]: %v\n", f.quickCheck[MDecomposed])
+ fmt.Fprintf(buf, " cmbForward: %v\n", f.combinesForward)
+ fmt.Fprintf(buf, " cmbBackward: %v\n", f.combinesBackward)
+ fmt.Fprintf(buf, " isOneWay: %v\n", f.isOneWay)
+ fmt.Fprintf(buf, " inDecomp: %v\n", f.inDecomp)
+ fmt.Fprintf(buf, " decomposition: %v\n", f.decomp)
+ fmt.Fprintf(buf, " expandedDecomp: %v\n", f.expandedDecomp)
+
+ return buf.String()
+}
+
+type Decomposition []int
+
+func (d Decomposition) String() string {
+ return fmt.Sprintf("%.4X", d)
+}
+
+func openReader(file string) (input io.ReadCloser) {
+ if *localFiles {
+ f, err := os.Open(file)
+ if err != nil {
+ logger.Fatal(err)
+ }
+ input = f
+ } else {
+ path := *url + file
+ resp, err := http.Get(path)
+ if err != nil {
+ logger.Fatal(err)
+ }
+ if resp.StatusCode != 200 {
+ logger.Fatal("bad GET status for "+file, resp.Status)
+ }
+ input = resp.Body
+ }
+ return
+}
+
+func parseDecomposition(s string, skipfirst bool) (a []int, e os.Error) {
+ decomp := strings.Split(s, " ")
+ if len(decomp) > 0 && skipfirst {
+ decomp = decomp[1:]
+ }
+ for _, d := range decomp {
+ point, err := strconv.Btoui64(d, 16)
+ if err != nil {
+ return a, err
+ }
+ a = append(a, int(point))
+ }
+ return a, nil
+}
+
+func parseCharacter(line string) {
+ field := strings.Split(line, ";")
+ if len(field) != NumField {
+ logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
+ }
+ x, err := strconv.Btoui64(field[FCodePoint], 16)
+ point := int(x)
+ if err != nil {
+ logger.Fatalf("%.5s...: %s", line, err)
+ }
+ if point == 0 {
+ return // not interesting and we use 0 as unset
+ }
+ if point > MaxChar {
+ logger.Fatalf("%5s: Rune %X > MaxChar (%X)", line, point, MaxChar)
+ return
+ }
+ state := SNormal
+ switch {
+ case strings.Index(field[FName], ", First>") > 0:
+ state = SFirst
+ case strings.Index(field[FName], ", Last>") > 0:
+ state = SLast
+ }
+ firstChar := lastChar + 1
+ lastChar = int(point)
+ if state != SLast {
+ firstChar = lastChar
+ }
+ x, err = strconv.Atoui64(field[FCanonicalCombiningClass])
+ if err != nil {
+ logger.Fatalf("%U: bad ccc field: %s", int(x), err)
+ }
+ ccc := uint8(x)
+ decmap := field[FDecompMapping]
+ exp, e := parseDecomposition(decmap, false)
+ isCompat := false
+ if e != nil {
+ if len(decmap) > 0 {
+ exp, e = parseDecomposition(decmap, true)
+ if e != nil {
+ logger.Fatalf(`%U: bad decomp |%v|: "%s"`, int(x), decmap, e)
+ }
+ isCompat = true
+ }
+ }
+ for i := firstChar; i <= lastChar; i++ {
+ char := &chars[i]
+ char.name = field[FName]
+ char.codePoint = i
+ char.forms[FCompatibility].decomp = exp
+ if !isCompat {
+ char.forms[FCanonical].decomp = exp
+ } else {
+ char.compatDecomp = true
+ }
+ if len(decmap) > 0 {
+ char.forms[FCompatibility].decomp = exp
+ }
+ char.ccc = ccc
+ char.state = SMissing
+ if i == lastChar {
+ char.state = state
+ }
+ }
+ return
+}
+
+func loadUnicodeData() {
+ f := openReader("UnicodeData.txt")
+ defer f.Close()
+ input := bufio.NewReader(f)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ parseCharacter(line[0 : len(line)-1])
+ }
+}
+
+var singlePointRe = regexp.MustCompile(`^([0-9A-F]+) *$`)
+
+// CompositionExclusions.txt has form:
+// 0958 # ...
+// See http://unicode.org/reports/tr44/ for full explanation
+func parseExclusion(line string) int {
+ comment := strings.Index(line, "#")
+ if comment >= 0 {
+ line = line[0:comment]
+ }
+ if len(line) == 0 {
+ return 0
+ }
+ matches := singlePointRe.FindStringSubmatch(line)
+ if len(matches) != 2 {
+ logger.Fatalf("%s: %d matches (expected 1)\n", line, len(matches))
+ }
+ point, err := strconv.Btoui64(matches[1], 16)
+ if err != nil {
+ logger.Fatalf("%.5s...: %s", line, err)
+ }
+ return int(point)
+}
+
+func loadCompositionExclusions() {
+ f := openReader("CompositionExclusions.txt")
+ defer f.Close()
+ input := bufio.NewReader(f)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ point := parseExclusion(line[0 : len(line)-1])
+ if point == 0 {
+ continue
+ }
+ c := &chars[point]
+ if c.excludeInComp {
+ logger.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint)
+ }
+ c.excludeInComp = true
+ }
+}
+
+// hasCompatDecomp returns true if any of the recursive
+// decompositions contains a compatibility expansion.
+// In this case, the character may not occur in NFK*.
+func hasCompatDecomp(rune int) bool {
+ c := &chars[rune]
+ if c.compatDecomp {
+ return true
+ }
+ for _, d := range c.forms[FCompatibility].decomp {
+ if hasCompatDecomp(d) {
+ return true
+ }
+ }
+ return false
+}
+
+// Hangul related constants.
+const (
+ HangulBase = 0xAC00
+ HangulEnd = 0xD7A4 // hangulBase + Jamo combinations (19 * 21 * 28)
+
+ JamoLBase = 0x1100
+ JamoLEnd = 0x1113
+ JamoVBase = 0x1161
+ JamoVEnd = 0x1176
+ JamoTBase = 0x11A8
+ JamoTEnd = 0x11C3
+)
+
+func isHangul(rune int) bool {
+ return HangulBase <= rune && rune < HangulEnd
+}
+
+func ccc(rune int) uint8 {
+ return chars[rune].ccc
+}
+
+// Insert a rune in a buffer, ordered by Canonical Combining Class.
+func insertOrdered(b Decomposition, rune int) Decomposition {
+ n := len(b)
+ b = append(b, 0)
+ cc := ccc(rune)
+ if cc > 0 {
+ // Use bubble sort.
+ for ; n > 0; n-- {
+ if ccc(b[n-1]) <= cc {
+ break
+ }
+ b[n] = b[n-1]
+ }
+ }
+ b[n] = rune
+ return b
+}
+
+// Recursively decompose.
+func decomposeRecursive(form int, rune int, d Decomposition) Decomposition {
+ if isHangul(rune) {
+ return d
+ }
+ dcomp := chars[rune].forms[form].decomp
+ if len(dcomp) == 0 {
+ return insertOrdered(d, rune)
+ }
+ for _, c := range dcomp {
+ d = decomposeRecursive(form, c, d)
+ }
+ return d
+}
+
+func completeCharFields(form int) {
+ // Phase 0: pre-expand decomposition.
+ for i := range chars {
+ f := &chars[i].forms[form]
+ if len(f.decomp) == 0 {
+ continue
+ }
+ exp := make(Decomposition, 0)
+ for _, c := range f.decomp {
+ exp = decomposeRecursive(form, c, exp)
+ }
+ f.expandedDecomp = exp
+ }
+
+ // Phase 1: composition exclusion, mark decomposition.
+ for i := range chars {
+ c := &chars[i]
+ f := &c.forms[form]
+
+ // Marks script-specific exclusions and version restricted.
+ f.isOneWay = c.excludeInComp
+
+ // Singletons
+ f.isOneWay = f.isOneWay || len(f.decomp) == 1
+
+ // Non-starter decompositions
+ if len(f.decomp) > 1 {
+ chk := c.ccc != 0 || chars[f.decomp[0]].ccc != 0
+ f.isOneWay = f.isOneWay || chk
+ }
+
+ // Runes that decompose into more than two runes.
+ f.isOneWay = f.isOneWay || len(f.decomp) > 2
+
+ if form == FCompatibility {
+ f.isOneWay = f.isOneWay || hasCompatDecomp(c.codePoint)
+ }
+
+ for _, rune := range f.decomp {
+ chars[rune].forms[form].inDecomp = true
+ }
+ }
+
+ // Phase 2: forward and backward combining.
+ for i := range chars {
+ c := &chars[i]
+ f := &c.forms[form]
+
+ if !f.isOneWay && len(f.decomp) == 2 {
+ f0 := &chars[f.decomp[0]].forms[form]
+ f1 := &chars[f.decomp[1]].forms[form]
+ if !f0.isOneWay {
+ f0.combinesForward = true
+ }
+ if !f1.isOneWay {
+ f1.combinesBackward = true
+ }
+ }
+ }
+
+ // Phase 3: quick check values.
+ for i := range chars {
+ c := &chars[i]
+ f := &c.forms[form]
+
+ switch {
+ case len(f.decomp) > 0:
+ f.quickCheck[MDecomposed] = QCNo
+ case isHangul(i):
+ f.quickCheck[MDecomposed] = QCNo
+ default:
+ f.quickCheck[MDecomposed] = QCYes
+ }
+ switch {
+ case f.isOneWay:
+ f.quickCheck[MComposed] = QCNo
+ case (i & 0xffff00) == JamoLBase:
+ f.quickCheck[MComposed] = QCYes
+ if JamoVBase <= i && i < JamoVEnd {
+ f.quickCheck[MComposed] = QCMaybe
+ f.combinesBackward = true
+ }
+ if JamoTBase <= i && i < JamoTEnd {
+ f.quickCheck[MComposed] = QCMaybe
+ f.combinesBackward = true
+ }
+ case !f.combinesBackward:
+ f.quickCheck[MComposed] = QCYes
+ default:
+ f.quickCheck[MComposed] = QCMaybe
+ }
+ }
+}
+
+func printBytes(b []byte, name string) {
+ fmt.Printf("// %s: %d bytes\n", name, len(b))
+ fmt.Printf("var %s = [...]byte {", name)
+ for i, c := range b {
+ switch {
+ case i%64 == 0:
+ fmt.Printf("\n// Bytes %x - %x\n", i, i+63)
+ case i%8 == 0:
+ fmt.Printf("\n")
+ }
+ fmt.Printf("0x%.2X, ", c)
+ }
+ fmt.Print("\n}\n\n")
+}
+
+// See forminfo.go for format.
+func makeEntry(f *FormInfo) uint16 {
+ e := uint16(0)
+ if f.combinesForward {
+ e |= 0x8
+ }
+ if f.quickCheck[MDecomposed] == QCNo {
+ e |= 0x1
+ }
+ switch f.quickCheck[MComposed] {
+ case QCYes:
+ case QCNo:
+ e |= 0x2
+ case QCMaybe:
+ e |= 0x6
+ default:
+ log.Fatalf("Illegal quickcheck value %d.", f.quickCheck[MComposed])
+ }
+ return e
+}
+
+// Bits
+// 0..8: CCC
+// 9..12: NF(C|D) qc bits.
+// 13..16: NFK(C|D) qc bits.
+func makeCharInfo(c Char) uint16 {
+ e := makeEntry(&c.forms[FCompatibility])
+ e = e<<4 | makeEntry(&c.forms[FCanonical])
+ e = e<<8 | uint16(c.ccc)
+ return e
+}
+
+func printCharInfoTables() int {
+ // Quick Check + CCC trie.
+ t := newNode()
+ for i, char := range chars {
+ v := makeCharInfo(char)
+ if v != 0 {
+ t.insert(i, v)
+ }
+ }
+ return t.printTables("charInfo")
+}
+
+func printDecompositionTables() int {
+ decompositions := bytes.NewBuffer(make([]byte, 0, 10000))
+ size := 0
+
+ // Map decompositions
+ positionMap := make(map[string]uint16)
+
+ // Store the uniqued decompositions in a byte buffer,
+ // preceded by their byte length.
+ for _, c := range chars {
+ for f := 0; f < 2; f++ {
+ d := c.forms[f].expandedDecomp
+ s := string([]int(d))
+ if _, ok := positionMap[s]; !ok {
+ p := decompositions.Len()
+ decompositions.WriteByte(uint8(len(s)))
+ decompositions.WriteString(s)
+ positionMap[s] = uint16(p)
+ }
+ }
+ }
+ b := decompositions.Bytes()
+ printBytes(b, "decomps")
+ size += len(b)
+
+ nfcT := newNode()
+ nfkcT := newNode()
+ for i, c := range chars {
+ d := c.forms[FCanonical].expandedDecomp
+ if len(d) != 0 {
+ nfcT.insert(i, positionMap[string([]int(d))])
+ if ccc(c.codePoint) != ccc(d[0]) {
+ // We assume the lead ccc of a decomposition is !=0 in this case.
+ if ccc(d[0]) == 0 {
+ logger.Fatal("Expected differing CCC to be non-zero.")
+ }
+ }
+ }
+ d = c.forms[FCompatibility].expandedDecomp
+ if len(d) != 0 {
+ nfkcT.insert(i, positionMap[string([]int(d))])
+ if ccc(c.codePoint) != ccc(d[0]) {
+ // We assume the lead ccc of a decomposition is !=0 in this case.
+ if ccc(d[0]) == 0 {
+ logger.Fatal("Expected differing CCC to be non-zero.")
+ }
+ }
+ }
+ }
+ size += nfcT.printTables("nfcDecomp")
+ size += nfkcT.printTables("nfkcDecomp")
+ return size
+}
+
+func contains(sa []string, s string) bool {
+ for _, a := range sa {
+ if a == s {
+ return true
+ }
+ }
+ return false
+}
+
+// Extract the version number from the URL.
+func version() string {
+ // From http://www.unicode.org/standard/versions/#Version_Numbering:
+ // for the later Unicode versions, data files are located in
+ // versioned directories.
+ fields := strings.Split(*url, "/")
+ for _, f := range fields {
+ if match, _ := regexp.MatchString(`[0-9]\.[0-9]\.[0-9]`, f); match {
+ return f
+ }
+ }
+ logger.Fatal("unknown version")
+ return "Unknown"
+}
+
+const fileHeader = `// Generated by running
+// maketables --tables=%s --url=%s
+// DO NOT EDIT
+
+package norm
+
+`
+
+func makeTables() {
+ size := 0
+ if *tablelist == "" {
+ return
+ }
+ list := strings.Split(*tablelist, ",")
+ if *tablelist == "all" {
+ list = []string{"decomp", "recomp", "info"}
+ }
+ fmt.Printf(fileHeader, *tablelist, *url)
+
+ fmt.Println("// Version is the Unicode edition from which the tables are derived.")
+ fmt.Printf("const Version = %q\n\n", version())
+
+ if contains(list, "decomp") {
+ size += printDecompositionTables()
+ }
+
+ if contains(list, "recomp") {
+ // Note that we use 32 bit keys, instead of 64 bit.
+ // This clips the bits of three entries, but we know
+ // this won't cause a collision. The compiler will catch
+ // any changes made to UnicodeData.txt that introduces
+ // a collision.
+ // Note that the recomposition map for NFC and NFKC
+ // are identical.
+
+ // Recomposition map
+ nrentries := 0
+ for _, c := range chars {
+ f := c.forms[FCanonical]
+ if !f.isOneWay && len(f.decomp) > 0 {
+ nrentries++
+ }
+ }
+ sz := nrentries * 8
+ size += sz
+ fmt.Printf("// recompMap: %d bytes (entries only)\n", sz)
+ fmt.Println("var recompMap = map[uint32]uint32{")
+ for i, c := range chars {
+ f := c.forms[FCanonical]
+ d := f.decomp
+ if !f.isOneWay && len(d) > 0 {
+ key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1]))
+ fmt.Printf("0x%.8X: 0x%.4X,\n", key, i)
+ }
+ }
+ fmt.Printf("}\n\n")
+ }
+
+ if contains(list, "info") {
+ size += printCharInfoTables()
+ }
+ fmt.Printf("// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size)
+}
+
+func printChars() {
+ if *verbose {
+ for _, c := range chars {
+ if !c.isValid() || c.state == SMissing {
+ continue
+ }
+ fmt.Println(c)
+ }
+ }
+}
+
+// verifyComputed does various consistency tests.
+func verifyComputed() {
+ for i, c := range chars {
+ for _, f := range c.forms {
+ isNo := (f.quickCheck[MDecomposed] == QCNo)
+ if (len(f.decomp) > 0) != isNo && !isHangul(i) {
+ log.Fatalf("%U: NF*D must be no if rune decomposes", i)
+ }
+
+ isMaybe := f.quickCheck[MComposed] == QCMaybe
+ if f.combinesBackward != isMaybe {
+ log.Fatalf("%U: NF*C must be maybe if combinesBackward", i)
+ }
+ }
+ }
+}
+
+var qcRe = regexp.MustCompile(`^([0-9A-F\.]+) *; (NF.*_QC); ([YNM]) #.*$`)
+
+// Use values in DerivedNormalizationProps.txt to compare against the
+// values we computed.
+// DerivedNormalizationProps.txt has form:
+// 00C0..00C5 ; NFD_QC; N # ...
+// 0374 ; NFD_QC; N # ...
+// See http://unicode.org/reports/tr44/ for full explanation
+func testDerived() {
+ if !*test {
+ return
+ }
+ f := openReader("DerivedNormalizationProps.txt")
+ defer f.Close()
+ input := bufio.NewReader(f)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ qc := qcRe.FindStringSubmatch(line)
+ if qc == nil {
+ continue
+ }
+ rng := strings.Split(qc[1], "..")
+ i, err := strconv.Btoui64(rng[0], 16)
+ if err != nil {
+ log.Fatal(err)
+ }
+ j := i
+ if len(rng) > 1 {
+ j, err = strconv.Btoui64(rng[1], 16)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ var ftype, mode int
+ qt := strings.TrimSpace(qc[2])
+ switch qt {
+ case "NFC_QC":
+ ftype, mode = FCanonical, MComposed
+ case "NFD_QC":
+ ftype, mode = FCanonical, MDecomposed
+ case "NFKC_QC":
+ ftype, mode = FCompatibility, MComposed
+ case "NFKD_QC":
+ ftype, mode = FCompatibility, MDecomposed
+ default:
+ log.Fatalf(`Unexpected quick check type "%s"`, qt)
+ }
+ var qr QCResult
+ switch qc[3] {
+ case "Y":
+ qr = QCYes
+ case "N":
+ qr = QCNo
+ case "M":
+ qr = QCMaybe
+ default:
+ log.Fatalf(`Unexpected quick check value "%s"`, qc[3])
+ }
+ var lastFailed bool
+ // Verify current
+ for ; i <= j; i++ {
+ c := &chars[int(i)]
+ c.forms[ftype].verified[mode] = true
+ curqr := c.forms[ftype].quickCheck[mode]
+ if curqr != qr {
+ if !lastFailed {
+ logger.Printf("%s: %.4X..%.4X -- %s\n",
+ qt, int(i), int(j), line[0:50])
+ }
+ logger.Printf("%U: FAILED %s (was %v need %v)\n",
+ int(i), qt, curqr, qr)
+ lastFailed = true
+ }
+ }
+ }
+ // Any unspecified value must be QCYes. Verify this.
+ for i, c := range chars {
+ for j, fd := range c.forms {
+ for k, qr := range fd.quickCheck {
+ if !fd.verified[k] && qr != QCYes {
+ m := "%U: FAIL F:%d M:%d (was %v need Yes) %s\n"
+ logger.Printf(m, i, j, k, qr, c.name)
+ }
+ }
+ }
+ }
+}
diff --git a/libgo/go/exp/norm/maketesttables.go b/libgo/go/exp/norm/maketesttables.go
new file mode 100644
index 00000000000..c5f6a64368d
--- /dev/null
+++ b/libgo/go/exp/norm/maketesttables.go
@@ -0,0 +1,42 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate test data for trie code.
+
+package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ printTestTables()
+}
+
+// We take the smallest, largest and an arbitrary value for each
+// of the UTF-8 sequence lengths.
+var testRunes = []int{
+ 0x01, 0x0C, 0x7F, // 1-byte sequences
+ 0x80, 0x100, 0x7FF, // 2-byte sequences
+ 0x800, 0x999, 0xFFFF, // 3-byte sequences
+ 0x10000, 0x10101, 0x10FFFF, // 4-byte sequences
+}
+
+const fileHeader = `// Generated by running
+// maketesttables
+// DO NOT EDIT
+
+package norm
+
+`
+
+func printTestTables() {
+ fmt.Print(fileHeader)
+ fmt.Printf("var testRunes = %#v\n\n", testRunes)
+ t := newNode()
+ for i, r := range testRunes {
+ t.insert(r, uint16(i))
+ }
+ t.printTables("testdata")
+}
diff --git a/libgo/go/exp/norm/norm_test.go b/libgo/go/exp/norm/norm_test.go
new file mode 100644
index 00000000000..12dacfcf300
--- /dev/null
+++ b/libgo/go/exp/norm/norm_test.go
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm_test
+
+import (
+ "testing"
+)
+
+func TestPlaceHolder(t *testing.T) {
+ // Does nothing, just allows the Makefile to be canonical
+ // while waiting for the package itself to be written.
+}
diff --git a/libgo/go/exp/norm/normalize.go b/libgo/go/exp/norm/normalize.go
new file mode 100644
index 00000000000..e9d18dd9ea9
--- /dev/null
+++ b/libgo/go/exp/norm/normalize.go
@@ -0,0 +1,99 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package norm contains types and functions for normalizing Unicode strings.
+package norm
+
+// A Form denotes a canonical representation of Unicode code points.
+// The Unicode-defined normalization and equivalence forms are:
+//
+// NFC Unicode Normalization Form C
+// NFD Unicode Normalization Form D
+// NFKC Unicode Normalization Form KC
+// NFKD Unicode Normalization Form KD
+//
+// For a Form f, this documentation uses the notation f(x) to mean
+// the bytes or string x converted to the given form.
+// A position n in x is called a boundary if conversion to the form can
+// proceed independently on both sides:
+// f(x) == append(f(x[0:n]), f(x[n:])...)
+//
+// References: http://unicode.org/reports/tr15/ and
+// http://unicode.org/notes/tn5/.
+type Form int
+
+const (
+ NFC Form = iota
+ NFD
+ NFKC
+ NFKD
+)
+
+// Bytes returns f(b). May return b if f(b) = b.
+func (f Form) Bytes(b []byte) []byte {
+ panic("not implemented")
+}
+
+// String returns f(s).
+func (f Form) String(s string) string {
+ panic("not implemented")
+}
+
+// IsNormal returns true if b == f(b).
+func (f Form) IsNormal(b []byte) bool {
+ panic("not implemented")
+}
+
+// IsNormalString returns true if s == f(s).
+func (f Form) IsNormalString(s string) bool {
+ panic("not implemented")
+}
+
+// Append returns f(append(out, b...)).
+// The buffer out must be empty or equal to f(out).
+func (f Form) Append(out, b []byte) []byte {
+ panic("not implemented")
+}
+
+// AppendString returns f(append(out, []byte(s))).
+// The buffer out must be empty or equal to f(out).
+func (f Form) AppendString(out []byte, s string) []byte {
+ panic("not implemented")
+}
+
+// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpan(b []byte) int {
+ panic("not implemented")
+}
+
+// QuickSpanString returns a boundary n such that b[0:n] == f(s[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpanString(s string) int {
+ panic("not implemented")
+}
+
+// FirstBoundary returns the position i of the first boundary in b.
+// It returns len(b), false if b contains no boundaries.
+func (f Form) FirstBoundary(b []byte) (i int, ok bool) {
+ panic("not implemented")
+}
+
+// FirstBoundaryInString return the position i of the first boundary in s.
+// It returns len(s), false if s contains no boundaries.
+func (f Form) FirstBoundaryInString(s string) (i int, ok bool) {
+ panic("not implemented")
+}
+
+// LastBoundaryIn returns the position i of the last boundary in b.
+// It returns 0, false if b contains no boundary.
+func (f Form) LastBoundary(b []byte) (i int, ok bool) {
+ panic("not implemented")
+}
+
+// LastBoundaryInString returns the position i of the last boundary in s.
+// It returns 0, false if s contains no boundary.
+func (f Form) LastBoundaryInString(s string) (i int, ok bool) {
+ panic("not implemented")
+}
diff --git a/libgo/go/exp/norm/tables.go b/libgo/go/exp/norm/tables.go
new file mode 100644
index 00000000000..76995c2fa18
--- /dev/null
+++ b/libgo/go/exp/norm/tables.go
@@ -0,0 +1,6580 @@
+// Generated by running
+// maketables --tables=all --url=http://www.unicode.org/Public/6.0.0/ucd/
+// DO NOT EDIT
+
+package norm
+
+// Version is the Unicode edition from which the tables are derived.
+const Version = "6.0.0"
+
+// decomps: 17618 bytes
+var decomps = [...]byte{
+ // Bytes 0 - 3f
+ 0x00, 0x01, 0x20, 0x03, 0x20, 0xCC, 0x88, 0x01,
+ 0x61, 0x03, 0x20, 0xCC, 0x84, 0x01, 0x32, 0x01,
+ 0x33, 0x03, 0x20, 0xCC, 0x81, 0x02, 0xCE, 0xBC,
+ 0x03, 0x20, 0xCC, 0xA7, 0x01, 0x31, 0x01, 0x6F,
+ 0x05, 0x31, 0xE2, 0x81, 0x84, 0x34, 0x05, 0x31,
+ 0xE2, 0x81, 0x84, 0x32, 0x05, 0x33, 0xE2, 0x81,
+ 0x84, 0x34, 0x03, 0x41, 0xCC, 0x80, 0x03, 0x41,
+ 0xCC, 0x81, 0x03, 0x41, 0xCC, 0x82, 0x03, 0x41,
+ // Bytes 40 - 7f
+ 0xCC, 0x83, 0x03, 0x41, 0xCC, 0x88, 0x03, 0x41,
+ 0xCC, 0x8A, 0x03, 0x43, 0xCC, 0xA7, 0x03, 0x45,
+ 0xCC, 0x80, 0x03, 0x45, 0xCC, 0x81, 0x03, 0x45,
+ 0xCC, 0x82, 0x03, 0x45, 0xCC, 0x88, 0x03, 0x49,
+ 0xCC, 0x80, 0x03, 0x49, 0xCC, 0x81, 0x03, 0x49,
+ 0xCC, 0x82, 0x03, 0x49, 0xCC, 0x88, 0x03, 0x4E,
+ 0xCC, 0x83, 0x03, 0x4F, 0xCC, 0x80, 0x03, 0x4F,
+ 0xCC, 0x81, 0x03, 0x4F, 0xCC, 0x82, 0x03, 0x4F,
+ // Bytes 80 - bf
+ 0xCC, 0x83, 0x03, 0x4F, 0xCC, 0x88, 0x03, 0x55,
+ 0xCC, 0x80, 0x03, 0x55, 0xCC, 0x81, 0x03, 0x55,
+ 0xCC, 0x82, 0x03, 0x55, 0xCC, 0x88, 0x03, 0x59,
+ 0xCC, 0x81, 0x03, 0x61, 0xCC, 0x80, 0x03, 0x61,
+ 0xCC, 0x81, 0x03, 0x61, 0xCC, 0x82, 0x03, 0x61,
+ 0xCC, 0x83, 0x03, 0x61, 0xCC, 0x88, 0x03, 0x61,
+ 0xCC, 0x8A, 0x03, 0x63, 0xCC, 0xA7, 0x03, 0x65,
+ 0xCC, 0x80, 0x03, 0x65, 0xCC, 0x81, 0x03, 0x65,
+ // Bytes c0 - ff
+ 0xCC, 0x82, 0x03, 0x65, 0xCC, 0x88, 0x03, 0x69,
+ 0xCC, 0x80, 0x03, 0x69, 0xCC, 0x81, 0x03, 0x69,
+ 0xCC, 0x82, 0x03, 0x69, 0xCC, 0x88, 0x03, 0x6E,
+ 0xCC, 0x83, 0x03, 0x6F, 0xCC, 0x80, 0x03, 0x6F,
+ 0xCC, 0x81, 0x03, 0x6F, 0xCC, 0x82, 0x03, 0x6F,
+ 0xCC, 0x83, 0x03, 0x6F, 0xCC, 0x88, 0x03, 0x75,
+ 0xCC, 0x80, 0x03, 0x75, 0xCC, 0x81, 0x03, 0x75,
+ 0xCC, 0x82, 0x03, 0x75, 0xCC, 0x88, 0x03, 0x79,
+ // Bytes 100 - 13f
+ 0xCC, 0x81, 0x03, 0x79, 0xCC, 0x88, 0x03, 0x41,
+ 0xCC, 0x84, 0x03, 0x61, 0xCC, 0x84, 0x03, 0x41,
+ 0xCC, 0x86, 0x03, 0x61, 0xCC, 0x86, 0x03, 0x41,
+ 0xCC, 0xA8, 0x03, 0x61, 0xCC, 0xA8, 0x03, 0x43,
+ 0xCC, 0x81, 0x03, 0x63, 0xCC, 0x81, 0x03, 0x43,
+ 0xCC, 0x82, 0x03, 0x63, 0xCC, 0x82, 0x03, 0x43,
+ 0xCC, 0x87, 0x03, 0x63, 0xCC, 0x87, 0x03, 0x43,
+ 0xCC, 0x8C, 0x03, 0x63, 0xCC, 0x8C, 0x03, 0x44,
+ // Bytes 140 - 17f
+ 0xCC, 0x8C, 0x03, 0x64, 0xCC, 0x8C, 0x03, 0x45,
+ 0xCC, 0x84, 0x03, 0x65, 0xCC, 0x84, 0x03, 0x45,
+ 0xCC, 0x86, 0x03, 0x65, 0xCC, 0x86, 0x03, 0x45,
+ 0xCC, 0x87, 0x03, 0x65, 0xCC, 0x87, 0x03, 0x45,
+ 0xCC, 0xA8, 0x03, 0x65, 0xCC, 0xA8, 0x03, 0x45,
+ 0xCC, 0x8C, 0x03, 0x65, 0xCC, 0x8C, 0x03, 0x47,
+ 0xCC, 0x82, 0x03, 0x67, 0xCC, 0x82, 0x03, 0x47,
+ 0xCC, 0x86, 0x03, 0x67, 0xCC, 0x86, 0x03, 0x47,
+ // Bytes 180 - 1bf
+ 0xCC, 0x87, 0x03, 0x67, 0xCC, 0x87, 0x03, 0x47,
+ 0xCC, 0xA7, 0x03, 0x67, 0xCC, 0xA7, 0x03, 0x48,
+ 0xCC, 0x82, 0x03, 0x68, 0xCC, 0x82, 0x03, 0x49,
+ 0xCC, 0x83, 0x03, 0x69, 0xCC, 0x83, 0x03, 0x49,
+ 0xCC, 0x84, 0x03, 0x69, 0xCC, 0x84, 0x03, 0x49,
+ 0xCC, 0x86, 0x03, 0x69, 0xCC, 0x86, 0x03, 0x49,
+ 0xCC, 0xA8, 0x03, 0x69, 0xCC, 0xA8, 0x03, 0x49,
+ 0xCC, 0x87, 0x02, 0x49, 0x4A, 0x02, 0x69, 0x6A,
+ // Bytes 1c0 - 1ff
+ 0x03, 0x4A, 0xCC, 0x82, 0x03, 0x6A, 0xCC, 0x82,
+ 0x03, 0x4B, 0xCC, 0xA7, 0x03, 0x6B, 0xCC, 0xA7,
+ 0x03, 0x4C, 0xCC, 0x81, 0x03, 0x6C, 0xCC, 0x81,
+ 0x03, 0x4C, 0xCC, 0xA7, 0x03, 0x6C, 0xCC, 0xA7,
+ 0x03, 0x4C, 0xCC, 0x8C, 0x03, 0x6C, 0xCC, 0x8C,
+ 0x03, 0x4C, 0xC2, 0xB7, 0x03, 0x6C, 0xC2, 0xB7,
+ 0x03, 0x4E, 0xCC, 0x81, 0x03, 0x6E, 0xCC, 0x81,
+ 0x03, 0x4E, 0xCC, 0xA7, 0x03, 0x6E, 0xCC, 0xA7,
+ // Bytes 200 - 23f
+ 0x03, 0x4E, 0xCC, 0x8C, 0x03, 0x6E, 0xCC, 0x8C,
+ 0x03, 0xCA, 0xBC, 0x6E, 0x03, 0x4F, 0xCC, 0x84,
+ 0x03, 0x6F, 0xCC, 0x84, 0x03, 0x4F, 0xCC, 0x86,
+ 0x03, 0x6F, 0xCC, 0x86, 0x03, 0x4F, 0xCC, 0x8B,
+ 0x03, 0x6F, 0xCC, 0x8B, 0x03, 0x52, 0xCC, 0x81,
+ 0x03, 0x72, 0xCC, 0x81, 0x03, 0x52, 0xCC, 0xA7,
+ 0x03, 0x72, 0xCC, 0xA7, 0x03, 0x52, 0xCC, 0x8C,
+ 0x03, 0x72, 0xCC, 0x8C, 0x03, 0x53, 0xCC, 0x81,
+ // Bytes 240 - 27f
+ 0x03, 0x73, 0xCC, 0x81, 0x03, 0x53, 0xCC, 0x82,
+ 0x03, 0x73, 0xCC, 0x82, 0x03, 0x53, 0xCC, 0xA7,
+ 0x03, 0x73, 0xCC, 0xA7, 0x03, 0x53, 0xCC, 0x8C,
+ 0x03, 0x73, 0xCC, 0x8C, 0x03, 0x54, 0xCC, 0xA7,
+ 0x03, 0x74, 0xCC, 0xA7, 0x03, 0x54, 0xCC, 0x8C,
+ 0x03, 0x74, 0xCC, 0x8C, 0x03, 0x55, 0xCC, 0x83,
+ 0x03, 0x75, 0xCC, 0x83, 0x03, 0x55, 0xCC, 0x84,
+ 0x03, 0x75, 0xCC, 0x84, 0x03, 0x55, 0xCC, 0x86,
+ // Bytes 280 - 2bf
+ 0x03, 0x75, 0xCC, 0x86, 0x03, 0x55, 0xCC, 0x8A,
+ 0x03, 0x75, 0xCC, 0x8A, 0x03, 0x55, 0xCC, 0x8B,
+ 0x03, 0x75, 0xCC, 0x8B, 0x03, 0x55, 0xCC, 0xA8,
+ 0x03, 0x75, 0xCC, 0xA8, 0x03, 0x57, 0xCC, 0x82,
+ 0x03, 0x77, 0xCC, 0x82, 0x03, 0x59, 0xCC, 0x82,
+ 0x03, 0x79, 0xCC, 0x82, 0x03, 0x59, 0xCC, 0x88,
+ 0x03, 0x5A, 0xCC, 0x81, 0x03, 0x7A, 0xCC, 0x81,
+ 0x03, 0x5A, 0xCC, 0x87, 0x03, 0x7A, 0xCC, 0x87,
+ // Bytes 2c0 - 2ff
+ 0x03, 0x5A, 0xCC, 0x8C, 0x03, 0x7A, 0xCC, 0x8C,
+ 0x01, 0x73, 0x03, 0x4F, 0xCC, 0x9B, 0x03, 0x6F,
+ 0xCC, 0x9B, 0x03, 0x55, 0xCC, 0x9B, 0x03, 0x75,
+ 0xCC, 0x9B, 0x04, 0x44, 0x5A, 0xCC, 0x8C, 0x04,
+ 0x44, 0x7A, 0xCC, 0x8C, 0x04, 0x64, 0x7A, 0xCC,
+ 0x8C, 0x02, 0x4C, 0x4A, 0x02, 0x4C, 0x6A, 0x02,
+ 0x6C, 0x6A, 0x02, 0x4E, 0x4A, 0x02, 0x4E, 0x6A,
+ 0x02, 0x6E, 0x6A, 0x03, 0x41, 0xCC, 0x8C, 0x03,
+ // Bytes 300 - 33f
+ 0x61, 0xCC, 0x8C, 0x03, 0x49, 0xCC, 0x8C, 0x03,
+ 0x69, 0xCC, 0x8C, 0x03, 0x4F, 0xCC, 0x8C, 0x03,
+ 0x6F, 0xCC, 0x8C, 0x03, 0x55, 0xCC, 0x8C, 0x03,
+ 0x75, 0xCC, 0x8C, 0x05, 0x55, 0xCC, 0x88, 0xCC,
+ 0x84, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x84, 0x05,
+ 0x55, 0xCC, 0x88, 0xCC, 0x81, 0x05, 0x75, 0xCC,
+ 0x88, 0xCC, 0x81, 0x05, 0x55, 0xCC, 0x88, 0xCC,
+ 0x8C, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x8C, 0x05,
+ // Bytes 340 - 37f
+ 0x55, 0xCC, 0x88, 0xCC, 0x80, 0x05, 0x75, 0xCC,
+ 0x88, 0xCC, 0x80, 0x05, 0x41, 0xCC, 0x88, 0xCC,
+ 0x84, 0x05, 0x61, 0xCC, 0x88, 0xCC, 0x84, 0x05,
+ 0x41, 0xCC, 0x87, 0xCC, 0x84, 0x05, 0x61, 0xCC,
+ 0x87, 0xCC, 0x84, 0x04, 0xC3, 0x86, 0xCC, 0x84,
+ 0x04, 0xC3, 0xA6, 0xCC, 0x84, 0x03, 0x47, 0xCC,
+ 0x8C, 0x03, 0x67, 0xCC, 0x8C, 0x03, 0x4B, 0xCC,
+ 0x8C, 0x03, 0x6B, 0xCC, 0x8C, 0x03, 0x4F, 0xCC,
+ // Bytes 380 - 3bf
+ 0xA8, 0x03, 0x6F, 0xCC, 0xA8, 0x05, 0x4F, 0xCC,
+ 0xA8, 0xCC, 0x84, 0x05, 0x6F, 0xCC, 0xA8, 0xCC,
+ 0x84, 0x04, 0xC6, 0xB7, 0xCC, 0x8C, 0x04, 0xCA,
+ 0x92, 0xCC, 0x8C, 0x03, 0x6A, 0xCC, 0x8C, 0x02,
+ 0x44, 0x5A, 0x02, 0x44, 0x7A, 0x02, 0x64, 0x7A,
+ 0x03, 0x47, 0xCC, 0x81, 0x03, 0x67, 0xCC, 0x81,
+ 0x03, 0x4E, 0xCC, 0x80, 0x03, 0x6E, 0xCC, 0x80,
+ 0x05, 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0x05, 0x61,
+ // Bytes 3c0 - 3ff
+ 0xCC, 0x8A, 0xCC, 0x81, 0x04, 0xC3, 0x86, 0xCC,
+ 0x81, 0x04, 0xC3, 0xA6, 0xCC, 0x81, 0x04, 0xC3,
+ 0x98, 0xCC, 0x81, 0x04, 0xC3, 0xB8, 0xCC, 0x81,
+ 0x03, 0x41, 0xCC, 0x8F, 0x03, 0x61, 0xCC, 0x8F,
+ 0x03, 0x41, 0xCC, 0x91, 0x03, 0x61, 0xCC, 0x91,
+ 0x03, 0x45, 0xCC, 0x8F, 0x03, 0x65, 0xCC, 0x8F,
+ 0x03, 0x45, 0xCC, 0x91, 0x03, 0x65, 0xCC, 0x91,
+ 0x03, 0x49, 0xCC, 0x8F, 0x03, 0x69, 0xCC, 0x8F,
+ // Bytes 400 - 43f
+ 0x03, 0x49, 0xCC, 0x91, 0x03, 0x69, 0xCC, 0x91,
+ 0x03, 0x4F, 0xCC, 0x8F, 0x03, 0x6F, 0xCC, 0x8F,
+ 0x03, 0x4F, 0xCC, 0x91, 0x03, 0x6F, 0xCC, 0x91,
+ 0x03, 0x52, 0xCC, 0x8F, 0x03, 0x72, 0xCC, 0x8F,
+ 0x03, 0x52, 0xCC, 0x91, 0x03, 0x72, 0xCC, 0x91,
+ 0x03, 0x55, 0xCC, 0x8F, 0x03, 0x75, 0xCC, 0x8F,
+ 0x03, 0x55, 0xCC, 0x91, 0x03, 0x75, 0xCC, 0x91,
+ 0x03, 0x53, 0xCC, 0xA6, 0x03, 0x73, 0xCC, 0xA6,
+ // Bytes 440 - 47f
+ 0x03, 0x54, 0xCC, 0xA6, 0x03, 0x74, 0xCC, 0xA6,
+ 0x03, 0x48, 0xCC, 0x8C, 0x03, 0x68, 0xCC, 0x8C,
+ 0x03, 0x41, 0xCC, 0x87, 0x03, 0x61, 0xCC, 0x87,
+ 0x03, 0x45, 0xCC, 0xA7, 0x03, 0x65, 0xCC, 0xA7,
+ 0x05, 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0x05, 0x6F,
+ 0xCC, 0x88, 0xCC, 0x84, 0x05, 0x4F, 0xCC, 0x83,
+ 0xCC, 0x84, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x84,
+ 0x03, 0x4F, 0xCC, 0x87, 0x03, 0x6F, 0xCC, 0x87,
+ // Bytes 480 - 4bf
+ 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0x05, 0x6F,
+ 0xCC, 0x87, 0xCC, 0x84, 0x03, 0x59, 0xCC, 0x84,
+ 0x03, 0x79, 0xCC, 0x84, 0x01, 0x68, 0x02, 0xC9,
+ 0xA6, 0x01, 0x6A, 0x01, 0x72, 0x02, 0xC9, 0xB9,
+ 0x02, 0xC9, 0xBB, 0x02, 0xCA, 0x81, 0x01, 0x77,
+ 0x01, 0x79, 0x03, 0x20, 0xCC, 0x86, 0x03, 0x20,
+ 0xCC, 0x87, 0x03, 0x20, 0xCC, 0x8A, 0x03, 0x20,
+ 0xCC, 0xA8, 0x03, 0x20, 0xCC, 0x83, 0x03, 0x20,
+ // Bytes 4c0 - 4ff
+ 0xCC, 0x8B, 0x02, 0xC9, 0xA3, 0x01, 0x6C, 0x01,
+ 0x78, 0x02, 0xCA, 0x95, 0x02, 0xCC, 0x80, 0x02,
+ 0xCC, 0x81, 0x02, 0xCC, 0x93, 0x04, 0xCC, 0x88,
+ 0xCC, 0x81, 0x02, 0xCA, 0xB9, 0x03, 0x20, 0xCD,
+ 0x85, 0x01, 0x3B, 0x04, 0xC2, 0xA8, 0xCC, 0x81,
+ 0x05, 0x20, 0xCC, 0x88, 0xCC, 0x81, 0x04, 0xCE,
+ 0x91, 0xCC, 0x81, 0x02, 0xC2, 0xB7, 0x04, 0xCE,
+ 0x95, 0xCC, 0x81, 0x04, 0xCE, 0x97, 0xCC, 0x81,
+ // Bytes 500 - 53f
+ 0x04, 0xCE, 0x99, 0xCC, 0x81, 0x04, 0xCE, 0x9F,
+ 0xCC, 0x81, 0x04, 0xCE, 0xA5, 0xCC, 0x81, 0x04,
+ 0xCE, 0xA9, 0xCC, 0x81, 0x06, 0xCE, 0xB9, 0xCC,
+ 0x88, 0xCC, 0x81, 0x04, 0xCE, 0x99, 0xCC, 0x88,
+ 0x04, 0xCE, 0xA5, 0xCC, 0x88, 0x04, 0xCE, 0xB1,
+ 0xCC, 0x81, 0x04, 0xCE, 0xB5, 0xCC, 0x81, 0x04,
+ 0xCE, 0xB7, 0xCC, 0x81, 0x04, 0xCE, 0xB9, 0xCC,
+ 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81,
+ // Bytes 540 - 57f
+ 0x04, 0xCE, 0xB9, 0xCC, 0x88, 0x04, 0xCF, 0x85,
+ 0xCC, 0x88, 0x04, 0xCE, 0xBF, 0xCC, 0x81, 0x04,
+ 0xCF, 0x85, 0xCC, 0x81, 0x04, 0xCF, 0x89, 0xCC,
+ 0x81, 0x02, 0xCE, 0xB2, 0x02, 0xCE, 0xB8, 0x02,
+ 0xCE, 0xA5, 0x04, 0xCF, 0x92, 0xCC, 0x81, 0x04,
+ 0xCF, 0x92, 0xCC, 0x88, 0x02, 0xCF, 0x86, 0x02,
+ 0xCF, 0x80, 0x02, 0xCE, 0xBA, 0x02, 0xCF, 0x81,
+ 0x02, 0xCF, 0x82, 0x02, 0xCE, 0x98, 0x02, 0xCE,
+ // Bytes 580 - 5bf
+ 0xB5, 0x02, 0xCE, 0xA3, 0x04, 0xD0, 0x95, 0xCC,
+ 0x80, 0x04, 0xD0, 0x95, 0xCC, 0x88, 0x04, 0xD0,
+ 0x93, 0xCC, 0x81, 0x04, 0xD0, 0x86, 0xCC, 0x88,
+ 0x04, 0xD0, 0x9A, 0xCC, 0x81, 0x04, 0xD0, 0x98,
+ 0xCC, 0x80, 0x04, 0xD0, 0xA3, 0xCC, 0x86, 0x04,
+ 0xD0, 0x98, 0xCC, 0x86, 0x04, 0xD0, 0xB8, 0xCC,
+ 0x86, 0x04, 0xD0, 0xB5, 0xCC, 0x80, 0x04, 0xD0,
+ 0xB5, 0xCC, 0x88, 0x04, 0xD0, 0xB3, 0xCC, 0x81,
+ // Bytes 5c0 - 5ff
+ 0x04, 0xD1, 0x96, 0xCC, 0x88, 0x04, 0xD0, 0xBA,
+ 0xCC, 0x81, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0x04,
+ 0xD1, 0x83, 0xCC, 0x86, 0x04, 0xD1, 0xB4, 0xCC,
+ 0x8F, 0x04, 0xD1, 0xB5, 0xCC, 0x8F, 0x04, 0xD0,
+ 0x96, 0xCC, 0x86, 0x04, 0xD0, 0xB6, 0xCC, 0x86,
+ 0x04, 0xD0, 0x90, 0xCC, 0x86, 0x04, 0xD0, 0xB0,
+ 0xCC, 0x86, 0x04, 0xD0, 0x90, 0xCC, 0x88, 0x04,
+ 0xD0, 0xB0, 0xCC, 0x88, 0x04, 0xD0, 0x95, 0xCC,
+ // Bytes 600 - 63f
+ 0x86, 0x04, 0xD0, 0xB5, 0xCC, 0x86, 0x04, 0xD3,
+ 0x98, 0xCC, 0x88, 0x04, 0xD3, 0x99, 0xCC, 0x88,
+ 0x04, 0xD0, 0x96, 0xCC, 0x88, 0x04, 0xD0, 0xB6,
+ 0xCC, 0x88, 0x04, 0xD0, 0x97, 0xCC, 0x88, 0x04,
+ 0xD0, 0xB7, 0xCC, 0x88, 0x04, 0xD0, 0x98, 0xCC,
+ 0x84, 0x04, 0xD0, 0xB8, 0xCC, 0x84, 0x04, 0xD0,
+ 0x98, 0xCC, 0x88, 0x04, 0xD0, 0xB8, 0xCC, 0x88,
+ 0x04, 0xD0, 0x9E, 0xCC, 0x88, 0x04, 0xD0, 0xBE,
+ // Bytes 640 - 67f
+ 0xCC, 0x88, 0x04, 0xD3, 0xA8, 0xCC, 0x88, 0x04,
+ 0xD3, 0xA9, 0xCC, 0x88, 0x04, 0xD0, 0xAD, 0xCC,
+ 0x88, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0x04, 0xD0,
+ 0xA3, 0xCC, 0x84, 0x04, 0xD1, 0x83, 0xCC, 0x84,
+ 0x04, 0xD0, 0xA3, 0xCC, 0x88, 0x04, 0xD1, 0x83,
+ 0xCC, 0x88, 0x04, 0xD0, 0xA3, 0xCC, 0x8B, 0x04,
+ 0xD1, 0x83, 0xCC, 0x8B, 0x04, 0xD0, 0xA7, 0xCC,
+ 0x88, 0x04, 0xD1, 0x87, 0xCC, 0x88, 0x04, 0xD0,
+ // Bytes 680 - 6bf
+ 0xAB, 0xCC, 0x88, 0x04, 0xD1, 0x8B, 0xCC, 0x88,
+ 0x04, 0xD5, 0xA5, 0xD6, 0x82, 0x04, 0xD8, 0xA7,
+ 0xD9, 0x93, 0x04, 0xD8, 0xA7, 0xD9, 0x94, 0x04,
+ 0xD9, 0x88, 0xD9, 0x94, 0x04, 0xD8, 0xA7, 0xD9,
+ 0x95, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0x04, 0xD8,
+ 0xA7, 0xD9, 0xB4, 0x04, 0xD9, 0x88, 0xD9, 0xB4,
+ 0x04, 0xDB, 0x87, 0xD9, 0xB4, 0x04, 0xD9, 0x8A,
+ 0xD9, 0xB4, 0x04, 0xDB, 0x95, 0xD9, 0x94, 0x04,
+ // Bytes 6c0 - 6ff
+ 0xDB, 0x81, 0xD9, 0x94, 0x04, 0xDB, 0x92, 0xD9,
+ 0x94, 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC,
+ 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x06,
+ 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x06, 0xE0,
+ 0xA4, 0x95, 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4,
+ 0x96, 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0x97,
+ 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0x9C, 0xE0,
+ 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4,
+ // Bytes 700 - 73f
+ 0xBC, 0x06, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4, 0xBC,
+ 0x06, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4, 0xBC, 0x06,
+ 0xE0, 0xA4, 0xAF, 0xE0, 0xA4, 0xBC, 0x06, 0xE0,
+ 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x06, 0xE0, 0xA7,
+ 0x87, 0xE0, 0xA7, 0x97, 0x06, 0xE0, 0xA6, 0xA1,
+ 0xE0, 0xA6, 0xBC, 0x06, 0xE0, 0xA6, 0xA2, 0xE0,
+ 0xA6, 0xBC, 0x06, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6,
+ 0xBC, 0x06, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8, 0xBC,
+ // Bytes 740 - 77f
+ 0x06, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8, 0xBC, 0x06,
+ 0xE0, 0xA8, 0x96, 0xE0, 0xA8, 0xBC, 0x06, 0xE0,
+ 0xA8, 0x97, 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xA8,
+ 0x9C, 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xA8, 0xAB,
+ 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xAD, 0x87, 0xE0,
+ 0xAD, 0x96, 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAC,
+ 0xBE, 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAD, 0x97,
+ 0x06, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC, 0xBC, 0x06,
+ // Bytes 780 - 7bf
+ 0xE0, 0xAC, 0xA2, 0xE0, 0xAC, 0xBC, 0x06, 0xE0,
+ 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x06, 0xE0, 0xAF,
+ 0x86, 0xE0, 0xAE, 0xBE, 0x06, 0xE0, 0xAF, 0x87,
+ 0xE0, 0xAE, 0xBE, 0x06, 0xE0, 0xAF, 0x86, 0xE0,
+ 0xAF, 0x97, 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1,
+ 0x96, 0x06, 0xE0, 0xB2, 0xBF, 0xE0, 0xB3, 0x95,
+ 0x06, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x06,
+ 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x06, 0xE0,
+ // Bytes 7c0 - 7ff
+ 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x09, 0xE0, 0xB3,
+ 0x86, 0xE0, 0xB3, 0x82, 0xE0, 0xB3, 0x95, 0x06,
+ 0xE0, 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x06, 0xE0,
+ 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x06, 0xE0, 0xB5,
+ 0x86, 0xE0, 0xB5, 0x97, 0x06, 0xE0, 0xB7, 0x99,
+ 0xE0, 0xB7, 0x8A, 0x06, 0xE0, 0xB7, 0x99, 0xE0,
+ 0xB7, 0x8F, 0x09, 0xE0, 0xB7, 0x99, 0xE0, 0xB7,
+ 0x8F, 0xE0, 0xB7, 0x8A, 0x06, 0xE0, 0xB7, 0x99,
+ // Bytes 800 - 83f
+ 0xE0, 0xB7, 0x9F, 0x06, 0xE0, 0xB9, 0x8D, 0xE0,
+ 0xB8, 0xB2, 0x06, 0xE0, 0xBB, 0x8D, 0xE0, 0xBA,
+ 0xB2, 0x06, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99,
+ 0x06, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x03,
+ 0xE0, 0xBC, 0x8B, 0x06, 0xE0, 0xBD, 0x82, 0xE0,
+ 0xBE, 0xB7, 0x06, 0xE0, 0xBD, 0x8C, 0xE0, 0xBE,
+ 0xB7, 0x06, 0xE0, 0xBD, 0x91, 0xE0, 0xBE, 0xB7,
+ 0x06, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7, 0x06,
+ // Bytes 840 - 87f
+ 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x06, 0xE0,
+ 0xBD, 0x80, 0xE0, 0xBE, 0xB5, 0x06, 0xE0, 0xBD,
+ 0xB1, 0xE0, 0xBD, 0xB2, 0x06, 0xE0, 0xBD, 0xB1,
+ 0xE0, 0xBD, 0xB4, 0x06, 0xE0, 0xBE, 0xB2, 0xE0,
+ 0xBE, 0x80, 0x09, 0xE0, 0xBE, 0xB2, 0xE0, 0xBD,
+ 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBE, 0xB3,
+ 0xE0, 0xBE, 0x80, 0x09, 0xE0, 0xBE, 0xB3, 0xE0,
+ 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBD,
+ // Bytes 880 - 8bf
+ 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBE, 0x92,
+ 0xE0, 0xBE, 0xB7, 0x06, 0xE0, 0xBE, 0x9C, 0xE0,
+ 0xBE, 0xB7, 0x06, 0xE0, 0xBE, 0xA1, 0xE0, 0xBE,
+ 0xB7, 0x06, 0xE0, 0xBE, 0xA6, 0xE0, 0xBE, 0xB7,
+ 0x06, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, 0xB7, 0x06,
+ 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x06, 0xE1,
+ 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x03, 0xE1, 0x83,
+ 0x9C, 0x06, 0xE1, 0xAC, 0x85, 0xE1, 0xAC, 0xB5,
+ // Bytes 8c0 - 8ff
+ 0x06, 0xE1, 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x06,
+ 0xE1, 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x06, 0xE1,
+ 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC,
+ 0x8D, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x91,
+ 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBA, 0xE1,
+ 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBC, 0xE1, 0xAC,
+ 0xB5, 0x06, 0xE1, 0xAC, 0xBE, 0xE1, 0xAC, 0xB5,
+ 0x06, 0xE1, 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x06,
+ // Bytes 900 - 93f
+ 0xE1, 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x41,
+ 0x02, 0xC3, 0x86, 0x01, 0x42, 0x01, 0x44, 0x01,
+ 0x45, 0x02, 0xC6, 0x8E, 0x01, 0x47, 0x01, 0x48,
+ 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4B, 0x01, 0x4C,
+ 0x01, 0x4D, 0x01, 0x4E, 0x01, 0x4F, 0x02, 0xC8,
+ 0xA2, 0x01, 0x50, 0x01, 0x52, 0x01, 0x54, 0x01,
+ 0x55, 0x01, 0x57, 0x02, 0xC9, 0x90, 0x02, 0xC9,
+ 0x91, 0x03, 0xE1, 0xB4, 0x82, 0x01, 0x62, 0x01,
+ // Bytes 940 - 97f
+ 0x64, 0x01, 0x65, 0x02, 0xC9, 0x99, 0x02, 0xC9,
+ 0x9B, 0x02, 0xC9, 0x9C, 0x01, 0x67, 0x01, 0x6B,
+ 0x01, 0x6D, 0x02, 0xC5, 0x8B, 0x02, 0xC9, 0x94,
+ 0x03, 0xE1, 0xB4, 0x96, 0x03, 0xE1, 0xB4, 0x97,
+ 0x01, 0x70, 0x01, 0x74, 0x01, 0x75, 0x03, 0xE1,
+ 0xB4, 0x9D, 0x02, 0xC9, 0xAF, 0x01, 0x76, 0x03,
+ 0xE1, 0xB4, 0xA5, 0x02, 0xCE, 0xB3, 0x02, 0xCE,
+ 0xB4, 0x02, 0xCF, 0x87, 0x01, 0x69, 0x02, 0xD0,
+ // Bytes 980 - 9bf
+ 0xBD, 0x02, 0xC9, 0x92, 0x01, 0x63, 0x02, 0xC9,
+ 0x95, 0x02, 0xC3, 0xB0, 0x01, 0x66, 0x02, 0xC9,
+ 0x9F, 0x02, 0xC9, 0xA1, 0x02, 0xC9, 0xA5, 0x02,
+ 0xC9, 0xA8, 0x02, 0xC9, 0xA9, 0x02, 0xC9, 0xAA,
+ 0x03, 0xE1, 0xB5, 0xBB, 0x02, 0xCA, 0x9D, 0x02,
+ 0xC9, 0xAD, 0x03, 0xE1, 0xB6, 0x85, 0x02, 0xCA,
+ 0x9F, 0x02, 0xC9, 0xB1, 0x02, 0xC9, 0xB0, 0x02,
+ 0xC9, 0xB2, 0x02, 0xC9, 0xB3, 0x02, 0xC9, 0xB4,
+ // Bytes 9c0 - 9ff
+ 0x02, 0xC9, 0xB5, 0x02, 0xC9, 0xB8, 0x02, 0xCA,
+ 0x82, 0x02, 0xCA, 0x83, 0x02, 0xC6, 0xAB, 0x02,
+ 0xCA, 0x89, 0x02, 0xCA, 0x8A, 0x03, 0xE1, 0xB4,
+ 0x9C, 0x02, 0xCA, 0x8B, 0x02, 0xCA, 0x8C, 0x01,
+ 0x7A, 0x02, 0xCA, 0x90, 0x02, 0xCA, 0x91, 0x02,
+ 0xCA, 0x92, 0x03, 0x41, 0xCC, 0xA5, 0x03, 0x61,
+ 0xCC, 0xA5, 0x03, 0x42, 0xCC, 0x87, 0x03, 0x62,
+ 0xCC, 0x87, 0x03, 0x42, 0xCC, 0xA3, 0x03, 0x62,
+ // Bytes a00 - a3f
+ 0xCC, 0xA3, 0x03, 0x42, 0xCC, 0xB1, 0x03, 0x62,
+ 0xCC, 0xB1, 0x05, 0x43, 0xCC, 0xA7, 0xCC, 0x81,
+ 0x05, 0x63, 0xCC, 0xA7, 0xCC, 0x81, 0x03, 0x44,
+ 0xCC, 0x87, 0x03, 0x64, 0xCC, 0x87, 0x03, 0x44,
+ 0xCC, 0xA3, 0x03, 0x64, 0xCC, 0xA3, 0x03, 0x44,
+ 0xCC, 0xB1, 0x03, 0x64, 0xCC, 0xB1, 0x03, 0x44,
+ 0xCC, 0xA7, 0x03, 0x64, 0xCC, 0xA7, 0x03, 0x44,
+ 0xCC, 0xAD, 0x03, 0x64, 0xCC, 0xAD, 0x05, 0x45,
+ // Bytes a40 - a7f
+ 0xCC, 0x84, 0xCC, 0x80, 0x05, 0x65, 0xCC, 0x84,
+ 0xCC, 0x80, 0x05, 0x45, 0xCC, 0x84, 0xCC, 0x81,
+ 0x05, 0x65, 0xCC, 0x84, 0xCC, 0x81, 0x03, 0x45,
+ 0xCC, 0xAD, 0x03, 0x65, 0xCC, 0xAD, 0x03, 0x45,
+ 0xCC, 0xB0, 0x03, 0x65, 0xCC, 0xB0, 0x05, 0x45,
+ 0xCC, 0xA7, 0xCC, 0x86, 0x05, 0x65, 0xCC, 0xA7,
+ 0xCC, 0x86, 0x03, 0x46, 0xCC, 0x87, 0x03, 0x66,
+ 0xCC, 0x87, 0x03, 0x47, 0xCC, 0x84, 0x03, 0x67,
+ // Bytes a80 - abf
+ 0xCC, 0x84, 0x03, 0x48, 0xCC, 0x87, 0x03, 0x68,
+ 0xCC, 0x87, 0x03, 0x48, 0xCC, 0xA3, 0x03, 0x68,
+ 0xCC, 0xA3, 0x03, 0x48, 0xCC, 0x88, 0x03, 0x68,
+ 0xCC, 0x88, 0x03, 0x48, 0xCC, 0xA7, 0x03, 0x68,
+ 0xCC, 0xA7, 0x03, 0x48, 0xCC, 0xAE, 0x03, 0x68,
+ 0xCC, 0xAE, 0x03, 0x49, 0xCC, 0xB0, 0x03, 0x69,
+ 0xCC, 0xB0, 0x05, 0x49, 0xCC, 0x88, 0xCC, 0x81,
+ 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81, 0x03, 0x4B,
+ // Bytes ac0 - aff
+ 0xCC, 0x81, 0x03, 0x6B, 0xCC, 0x81, 0x03, 0x4B,
+ 0xCC, 0xA3, 0x03, 0x6B, 0xCC, 0xA3, 0x03, 0x4B,
+ 0xCC, 0xB1, 0x03, 0x6B, 0xCC, 0xB1, 0x03, 0x4C,
+ 0xCC, 0xA3, 0x03, 0x6C, 0xCC, 0xA3, 0x05, 0x4C,
+ 0xCC, 0xA3, 0xCC, 0x84, 0x05, 0x6C, 0xCC, 0xA3,
+ 0xCC, 0x84, 0x03, 0x4C, 0xCC, 0xB1, 0x03, 0x6C,
+ 0xCC, 0xB1, 0x03, 0x4C, 0xCC, 0xAD, 0x03, 0x6C,
+ 0xCC, 0xAD, 0x03, 0x4D, 0xCC, 0x81, 0x03, 0x6D,
+ // Bytes b00 - b3f
+ 0xCC, 0x81, 0x03, 0x4D, 0xCC, 0x87, 0x03, 0x6D,
+ 0xCC, 0x87, 0x03, 0x4D, 0xCC, 0xA3, 0x03, 0x6D,
+ 0xCC, 0xA3, 0x03, 0x4E, 0xCC, 0x87, 0x03, 0x6E,
+ 0xCC, 0x87, 0x03, 0x4E, 0xCC, 0xA3, 0x03, 0x6E,
+ 0xCC, 0xA3, 0x03, 0x4E, 0xCC, 0xB1, 0x03, 0x6E,
+ 0xCC, 0xB1, 0x03, 0x4E, 0xCC, 0xAD, 0x03, 0x6E,
+ 0xCC, 0xAD, 0x05, 0x4F, 0xCC, 0x83, 0xCC, 0x81,
+ 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x81, 0x05, 0x4F,
+ // Bytes b40 - b7f
+ 0xCC, 0x83, 0xCC, 0x88, 0x05, 0x6F, 0xCC, 0x83,
+ 0xCC, 0x88, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80,
+ 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0x05, 0x4F,
+ 0xCC, 0x84, 0xCC, 0x81, 0x05, 0x6F, 0xCC, 0x84,
+ 0xCC, 0x81, 0x03, 0x50, 0xCC, 0x81, 0x03, 0x70,
+ 0xCC, 0x81, 0x03, 0x50, 0xCC, 0x87, 0x03, 0x70,
+ 0xCC, 0x87, 0x03, 0x52, 0xCC, 0x87, 0x03, 0x72,
+ 0xCC, 0x87, 0x03, 0x52, 0xCC, 0xA3, 0x03, 0x72,
+ // Bytes b80 - bbf
+ 0xCC, 0xA3, 0x05, 0x52, 0xCC, 0xA3, 0xCC, 0x84,
+ 0x05, 0x72, 0xCC, 0xA3, 0xCC, 0x84, 0x03, 0x52,
+ 0xCC, 0xB1, 0x03, 0x72, 0xCC, 0xB1, 0x03, 0x53,
+ 0xCC, 0x87, 0x03, 0x73, 0xCC, 0x87, 0x03, 0x53,
+ 0xCC, 0xA3, 0x03, 0x73, 0xCC, 0xA3, 0x05, 0x53,
+ 0xCC, 0x81, 0xCC, 0x87, 0x05, 0x73, 0xCC, 0x81,
+ 0xCC, 0x87, 0x05, 0x53, 0xCC, 0x8C, 0xCC, 0x87,
+ 0x05, 0x73, 0xCC, 0x8C, 0xCC, 0x87, 0x05, 0x53,
+ // Bytes bc0 - bff
+ 0xCC, 0xA3, 0xCC, 0x87, 0x05, 0x73, 0xCC, 0xA3,
+ 0xCC, 0x87, 0x03, 0x54, 0xCC, 0x87, 0x03, 0x74,
+ 0xCC, 0x87, 0x03, 0x54, 0xCC, 0xA3, 0x03, 0x74,
+ 0xCC, 0xA3, 0x03, 0x54, 0xCC, 0xB1, 0x03, 0x74,
+ 0xCC, 0xB1, 0x03, 0x54, 0xCC, 0xAD, 0x03, 0x74,
+ 0xCC, 0xAD, 0x03, 0x55, 0xCC, 0xA4, 0x03, 0x75,
+ 0xCC, 0xA4, 0x03, 0x55, 0xCC, 0xB0, 0x03, 0x75,
+ 0xCC, 0xB0, 0x03, 0x55, 0xCC, 0xAD, 0x03, 0x75,
+ // Bytes c00 - c3f
+ 0xCC, 0xAD, 0x05, 0x55, 0xCC, 0x83, 0xCC, 0x81,
+ 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81, 0x05, 0x55,
+ 0xCC, 0x84, 0xCC, 0x88, 0x05, 0x75, 0xCC, 0x84,
+ 0xCC, 0x88, 0x03, 0x56, 0xCC, 0x83, 0x03, 0x76,
+ 0xCC, 0x83, 0x03, 0x56, 0xCC, 0xA3, 0x03, 0x76,
+ 0xCC, 0xA3, 0x03, 0x57, 0xCC, 0x80, 0x03, 0x77,
+ 0xCC, 0x80, 0x03, 0x57, 0xCC, 0x81, 0x03, 0x77,
+ 0xCC, 0x81, 0x03, 0x57, 0xCC, 0x88, 0x03, 0x77,
+ // Bytes c40 - c7f
+ 0xCC, 0x88, 0x03, 0x57, 0xCC, 0x87, 0x03, 0x77,
+ 0xCC, 0x87, 0x03, 0x57, 0xCC, 0xA3, 0x03, 0x77,
+ 0xCC, 0xA3, 0x03, 0x58, 0xCC, 0x87, 0x03, 0x78,
+ 0xCC, 0x87, 0x03, 0x58, 0xCC, 0x88, 0x03, 0x78,
+ 0xCC, 0x88, 0x03, 0x59, 0xCC, 0x87, 0x03, 0x79,
+ 0xCC, 0x87, 0x03, 0x5A, 0xCC, 0x82, 0x03, 0x7A,
+ 0xCC, 0x82, 0x03, 0x5A, 0xCC, 0xA3, 0x03, 0x7A,
+ 0xCC, 0xA3, 0x03, 0x5A, 0xCC, 0xB1, 0x03, 0x7A,
+ // Bytes c80 - cbf
+ 0xCC, 0xB1, 0x03, 0x68, 0xCC, 0xB1, 0x03, 0x74,
+ 0xCC, 0x88, 0x03, 0x77, 0xCC, 0x8A, 0x03, 0x79,
+ 0xCC, 0x8A, 0x03, 0x61, 0xCA, 0xBE, 0x04, 0xC5,
+ 0xBF, 0xCC, 0x87, 0x03, 0x41, 0xCC, 0xA3, 0x03,
+ 0x61, 0xCC, 0xA3, 0x03, 0x41, 0xCC, 0x89, 0x03,
+ 0x61, 0xCC, 0x89, 0x05, 0x41, 0xCC, 0x82, 0xCC,
+ 0x81, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x81, 0x05,
+ 0x41, 0xCC, 0x82, 0xCC, 0x80, 0x05, 0x61, 0xCC,
+ // Bytes cc0 - cff
+ 0x82, 0xCC, 0x80, 0x05, 0x41, 0xCC, 0x82, 0xCC,
+ 0x89, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x89, 0x05,
+ 0x41, 0xCC, 0x82, 0xCC, 0x83, 0x05, 0x61, 0xCC,
+ 0x82, 0xCC, 0x83, 0x05, 0x41, 0xCC, 0xA3, 0xCC,
+ 0x82, 0x05, 0x61, 0xCC, 0xA3, 0xCC, 0x82, 0x05,
+ 0x41, 0xCC, 0x86, 0xCC, 0x81, 0x05, 0x61, 0xCC,
+ 0x86, 0xCC, 0x81, 0x05, 0x41, 0xCC, 0x86, 0xCC,
+ 0x80, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x80, 0x05,
+ // Bytes d00 - d3f
+ 0x41, 0xCC, 0x86, 0xCC, 0x89, 0x05, 0x61, 0xCC,
+ 0x86, 0xCC, 0x89, 0x05, 0x41, 0xCC, 0x86, 0xCC,
+ 0x83, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83, 0x05,
+ 0x41, 0xCC, 0xA3, 0xCC, 0x86, 0x05, 0x61, 0xCC,
+ 0xA3, 0xCC, 0x86, 0x03, 0x45, 0xCC, 0xA3, 0x03,
+ 0x65, 0xCC, 0xA3, 0x03, 0x45, 0xCC, 0x89, 0x03,
+ 0x65, 0xCC, 0x89, 0x03, 0x45, 0xCC, 0x83, 0x03,
+ 0x65, 0xCC, 0x83, 0x05, 0x45, 0xCC, 0x82, 0xCC,
+ // Bytes d40 - d7f
+ 0x81, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0x05,
+ 0x45, 0xCC, 0x82, 0xCC, 0x80, 0x05, 0x65, 0xCC,
+ 0x82, 0xCC, 0x80, 0x05, 0x45, 0xCC, 0x82, 0xCC,
+ 0x89, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x89, 0x05,
+ 0x45, 0xCC, 0x82, 0xCC, 0x83, 0x05, 0x65, 0xCC,
+ 0x82, 0xCC, 0x83, 0x05, 0x45, 0xCC, 0xA3, 0xCC,
+ 0x82, 0x05, 0x65, 0xCC, 0xA3, 0xCC, 0x82, 0x03,
+ 0x49, 0xCC, 0x89, 0x03, 0x69, 0xCC, 0x89, 0x03,
+ // Bytes d80 - dbf
+ 0x49, 0xCC, 0xA3, 0x03, 0x69, 0xCC, 0xA3, 0x03,
+ 0x4F, 0xCC, 0xA3, 0x03, 0x6F, 0xCC, 0xA3, 0x03,
+ 0x4F, 0xCC, 0x89, 0x03, 0x6F, 0xCC, 0x89, 0x05,
+ 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0x05, 0x6F, 0xCC,
+ 0x82, 0xCC, 0x81, 0x05, 0x4F, 0xCC, 0x82, 0xCC,
+ 0x80, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0x05,
+ 0x4F, 0xCC, 0x82, 0xCC, 0x89, 0x05, 0x6F, 0xCC,
+ 0x82, 0xCC, 0x89, 0x05, 0x4F, 0xCC, 0x82, 0xCC,
+ // Bytes dc0 - dff
+ 0x83, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x83, 0x05,
+ 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0x05, 0x6F, 0xCC,
+ 0xA3, 0xCC, 0x82, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
+ 0x81, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x81, 0x05,
+ 0x4F, 0xCC, 0x9B, 0xCC, 0x80, 0x05, 0x6F, 0xCC,
+ 0x9B, 0xCC, 0x80, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
+ 0x89, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, 0x05,
+ 0x4F, 0xCC, 0x9B, 0xCC, 0x83, 0x05, 0x6F, 0xCC,
+ // Bytes e00 - e3f
+ 0x9B, 0xCC, 0x83, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
+ 0xA3, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0x03,
+ 0x55, 0xCC, 0xA3, 0x03, 0x75, 0xCC, 0xA3, 0x03,
+ 0x55, 0xCC, 0x89, 0x03, 0x75, 0xCC, 0x89, 0x05,
+ 0x55, 0xCC, 0x9B, 0xCC, 0x81, 0x05, 0x75, 0xCC,
+ 0x9B, 0xCC, 0x81, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
+ 0x80, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x80, 0x05,
+ 0x55, 0xCC, 0x9B, 0xCC, 0x89, 0x05, 0x75, 0xCC,
+ // Bytes e40 - e7f
+ 0x9B, 0xCC, 0x89, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
+ 0x83, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83, 0x05,
+ 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0x05, 0x75, 0xCC,
+ 0x9B, 0xCC, 0xA3, 0x03, 0x59, 0xCC, 0x80, 0x03,
+ 0x79, 0xCC, 0x80, 0x03, 0x59, 0xCC, 0xA3, 0x03,
+ 0x79, 0xCC, 0xA3, 0x03, 0x59, 0xCC, 0x89, 0x03,
+ 0x79, 0xCC, 0x89, 0x03, 0x59, 0xCC, 0x83, 0x03,
+ 0x79, 0xCC, 0x83, 0x04, 0xCE, 0xB1, 0xCC, 0x93,
+ // Bytes e80 - ebf
+ 0x04, 0xCE, 0xB1, 0xCC, 0x94, 0x06, 0xCE, 0xB1,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC, 0x93,
+ 0xCC, 0x81, 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCC,
+ 0x81, 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0x04,
+ 0xCE, 0x91, 0xCC, 0x93, 0x04, 0xCE, 0x91, 0xCC,
+ 0x94, 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80,
+ // Bytes ec0 - eff
+ 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0x06,
+ 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE,
+ 0x91, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0x91,
+ 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0x91, 0xCC,
+ 0x94, 0xCD, 0x82, 0x04, 0xCE, 0xB5, 0xCC, 0x93,
+ 0x04, 0xCE, 0xB5, 0xCC, 0x94, 0x06, 0xCE, 0xB5,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0xB5, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xB5, 0xCC, 0x93,
+ // Bytes f00 - f3f
+ 0xCC, 0x81, 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC,
+ 0x81, 0x04, 0xCE, 0x95, 0xCC, 0x93, 0x04, 0xCE,
+ 0x95, 0xCC, 0x94, 0x06, 0xCE, 0x95, 0xCC, 0x93,
+ 0xCC, 0x80, 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC,
+ 0x80, 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81,
+ 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0x04,
+ 0xCE, 0xB7, 0xCC, 0x93, 0x04, 0xCE, 0xB7, 0xCC,
+ 0x94, 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80,
+ // Bytes f40 - f7f
+ 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0x06,
+ 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE,
+ 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xB7,
+ 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0xB7, 0xCC,
+ 0x94, 0xCD, 0x82, 0x04, 0xCE, 0x97, 0xCC, 0x93,
+ 0x04, 0xCE, 0x97, 0xCC, 0x94, 0x06, 0xCE, 0x97,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0x97, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x97, 0xCC, 0x93,
+ // Bytes f80 - fbf
+ 0xCC, 0x81, 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCC,
+ 0x81, 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82,
+ 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0x04,
+ 0xCE, 0xB9, 0xCC, 0x93, 0x04, 0xCE, 0xB9, 0xCC,
+ 0x94, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0x06,
+ 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE,
+ 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xB9,
+ // Bytes fc0 - fff
+ 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0xB9, 0xCC,
+ 0x94, 0xCD, 0x82, 0x04, 0xCE, 0x99, 0xCC, 0x93,
+ 0x04, 0xCE, 0x99, 0xCC, 0x94, 0x06, 0xCE, 0x99,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0x99, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x99, 0xCC, 0x93,
+ 0xCC, 0x81, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC,
+ 0x81, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82,
+ 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0x04,
+ // Bytes 1000 - 103f
+ 0xCE, 0xBF, 0xCC, 0x93, 0x04, 0xCE, 0xBF, 0xCC,
+ 0x94, 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0x06,
+ 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE,
+ 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0x04, 0xCE, 0x9F,
+ 0xCC, 0x93, 0x04, 0xCE, 0x9F, 0xCC, 0x94, 0x06,
+ 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE,
+ 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x9F,
+ // Bytes 1040 - 107f
+ 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, 0x9F, 0xCC,
+ 0x94, 0xCC, 0x81, 0x04, 0xCF, 0x85, 0xCC, 0x93,
+ 0x04, 0xCF, 0x85, 0xCC, 0x94, 0x06, 0xCF, 0x85,
+ 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCF, 0x85, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCF, 0x85, 0xCC, 0x93,
+ 0xCC, 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC,
+ 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82,
+ 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0x04,
+ // Bytes 1080 - 10bf
+ 0xCE, 0xA5, 0xCC, 0x94, 0x06, 0xCE, 0xA5, 0xCC,
+ 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xA5, 0xCC, 0x94,
+ 0xCC, 0x81, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD,
+ 0x82, 0x04, 0xCF, 0x89, 0xCC, 0x93, 0x04, 0xCF,
+ 0x89, 0xCC, 0x94, 0x06, 0xCF, 0x89, 0xCC, 0x93,
+ 0xCC, 0x80, 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCC,
+ 0x80, 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81,
+ 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0x06,
+ // Bytes 10c0 - 10ff
+ 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCF,
+ 0x89, 0xCC, 0x94, 0xCD, 0x82, 0x04, 0xCE, 0xA9,
+ 0xCC, 0x93, 0x04, 0xCE, 0xA9, 0xCC, 0x94, 0x06,
+ 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE,
+ 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xA9,
+ 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, 0xA9, 0xCC,
+ 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xA9, 0xCC, 0x93,
+ 0xCD, 0x82, 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD,
+ // Bytes 1100 - 113f
+ 0x82, 0x04, 0xCE, 0xB1, 0xCC, 0x80, 0x04, 0xCE,
+ 0xB5, 0xCC, 0x80, 0x04, 0xCE, 0xB7, 0xCC, 0x80,
+ 0x04, 0xCE, 0xB9, 0xCC, 0x80, 0x04, 0xCE, 0xBF,
+ 0xCC, 0x80, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0x04,
+ 0xCF, 0x89, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC,
+ 0x93, 0xCD, 0x85, 0x06, 0xCE, 0xB1, 0xCC, 0x94,
+ 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCC,
+ 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC, 0x94,
+ // Bytes 1140 - 117f
+ 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE, 0xB1,
+ 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE,
+ 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08,
+ 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
+ 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0x06,
+ 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE,
+ 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08,
+ // Bytes 1180 - 11bf
+ 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
+ 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
+ 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81,
+ 0xCD, 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCD,
+ 0x82, 0xCD, 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x94,
+ 0xCD, 0x82, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC, 0x94,
+ 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC,
+ // Bytes 11c0 - 11ff
+ 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC, 0x94,
+ 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE, 0xB7,
+ 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE,
+ 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08,
+ 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
+ 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0x06,
+ 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE,
+ // Bytes 1200 - 123f
+ 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08,
+ 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
+ 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
+ 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81,
+ 0xCD, 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD,
+ 0x82, 0xCD, 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x94,
+ 0xCD, 0x82, 0xCD, 0x85, 0x06, 0xCF, 0x89, 0xCC,
+ 0x93, 0xCD, 0x85, 0x06, 0xCF, 0x89, 0xCC, 0x94,
+ // Bytes 1240 - 127f
+ 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCC,
+ 0x80, 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC, 0x94,
+ 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC,
+ 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCF, 0x89,
+ 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCF,
+ 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08,
+ 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85,
+ 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0x06,
+ // Bytes 1280 - 12bf
+ 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE,
+ 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08,
+ 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85,
+ 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
+ 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81,
+ 0xCD, 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCD,
+ 0x82, 0xCD, 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x94,
+ 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE, 0xB1, 0xCC,
+ // Bytes 12c0 - 12ff
+ 0x86, 0x04, 0xCE, 0xB1, 0xCC, 0x84, 0x06, 0xCE,
+ 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0x04, 0xCE, 0xB1,
+ 0xCD, 0x85, 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD,
+ 0x85, 0x04, 0xCE, 0xB1, 0xCD, 0x82, 0x06, 0xCE,
+ 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE, 0x91,
+ 0xCC, 0x86, 0x04, 0xCE, 0x91, 0xCC, 0x84, 0x04,
+ 0xCE, 0x91, 0xCC, 0x80, 0x04, 0xCE, 0x91, 0xCD,
+ 0x85, 0x03, 0x20, 0xCC, 0x93, 0x02, 0xCE, 0xB9,
+ // Bytes 1300 - 133f
+ 0x03, 0x20, 0xCD, 0x82, 0x04, 0xC2, 0xA8, 0xCD,
+ 0x82, 0x05, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0x06,
+ 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0x04, 0xCE,
+ 0xB7, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC, 0x81,
+ 0xCD, 0x85, 0x04, 0xCE, 0xB7, 0xCD, 0x82, 0x06,
+ 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE,
+ 0x95, 0xCC, 0x80, 0x04, 0xCE, 0x97, 0xCC, 0x80,
+ 0x04, 0xCE, 0x97, 0xCD, 0x85, 0x05, 0xE1, 0xBE,
+ // Bytes 1340 - 137f
+ 0xBF, 0xCC, 0x80, 0x05, 0x20, 0xCC, 0x93, 0xCC,
+ 0x80, 0x05, 0xE1, 0xBE, 0xBF, 0xCC, 0x81, 0x05,
+ 0x20, 0xCC, 0x93, 0xCC, 0x81, 0x05, 0xE1, 0xBE,
+ 0xBF, 0xCD, 0x82, 0x05, 0x20, 0xCC, 0x93, 0xCD,
+ 0x82, 0x04, 0xCE, 0xB9, 0xCC, 0x86, 0x04, 0xCE,
+ 0xB9, 0xCC, 0x84, 0x06, 0xCE, 0xB9, 0xCC, 0x88,
+ 0xCC, 0x80, 0x04, 0xCE, 0xB9, 0xCD, 0x82, 0x06,
+ 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0x04, 0xCE,
+ // Bytes 1380 - 13bf
+ 0x99, 0xCC, 0x86, 0x04, 0xCE, 0x99, 0xCC, 0x84,
+ 0x04, 0xCE, 0x99, 0xCC, 0x80, 0x05, 0xE1, 0xBF,
+ 0xBE, 0xCC, 0x80, 0x05, 0x20, 0xCC, 0x94, 0xCC,
+ 0x80, 0x05, 0xE1, 0xBF, 0xBE, 0xCC, 0x81, 0x05,
+ 0x20, 0xCC, 0x94, 0xCC, 0x81, 0x05, 0xE1, 0xBF,
+ 0xBE, 0xCD, 0x82, 0x05, 0x20, 0xCC, 0x94, 0xCD,
+ 0x82, 0x04, 0xCF, 0x85, 0xCC, 0x86, 0x04, 0xCF,
+ 0x85, 0xCC, 0x84, 0x06, 0xCF, 0x85, 0xCC, 0x88,
+ // Bytes 13c0 - 13ff
+ 0xCC, 0x80, 0x04, 0xCF, 0x81, 0xCC, 0x93, 0x04,
+ 0xCF, 0x81, 0xCC, 0x94, 0x04, 0xCF, 0x85, 0xCD,
+ 0x82, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82,
+ 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0x04, 0xCE, 0xA5,
+ 0xCC, 0x84, 0x04, 0xCE, 0xA5, 0xCC, 0x80, 0x04,
+ 0xCE, 0xA1, 0xCC, 0x94, 0x04, 0xC2, 0xA8, 0xCC,
+ 0x80, 0x05, 0x20, 0xCC, 0x88, 0xCC, 0x80, 0x01,
+ 0x60, 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85,
+ // Bytes 1400 - 143f
+ 0x04, 0xCF, 0x89, 0xCD, 0x85, 0x06, 0xCF, 0x89,
+ 0xCC, 0x81, 0xCD, 0x85, 0x04, 0xCF, 0x89, 0xCD,
+ 0x82, 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85,
+ 0x04, 0xCE, 0x9F, 0xCC, 0x80, 0x04, 0xCE, 0xA9,
+ 0xCC, 0x80, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0x02,
+ 0xC2, 0xB4, 0x03, 0x20, 0xCC, 0x94, 0x03, 0xE2,
+ 0x80, 0x82, 0x03, 0xE2, 0x80, 0x83, 0x03, 0xE2,
+ 0x80, 0x90, 0x03, 0x20, 0xCC, 0xB3, 0x01, 0x2E,
+ // Bytes 1440 - 147f
+ 0x02, 0x2E, 0x2E, 0x03, 0x2E, 0x2E, 0x2E, 0x06,
+ 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x09, 0xE2,
+ 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ 0x06, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x09,
+ 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, 0x80,
+ 0xB5, 0x02, 0x21, 0x21, 0x03, 0x20, 0xCC, 0x85,
+ 0x02, 0x3F, 0x3F, 0x02, 0x3F, 0x21, 0x02, 0x21,
+ 0x3F, 0x0C, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ // Bytes 1480 - 14bf
+ 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x01, 0x30,
+ 0x01, 0x34, 0x01, 0x35, 0x01, 0x36, 0x01, 0x37,
+ 0x01, 0x38, 0x01, 0x39, 0x01, 0x2B, 0x03, 0xE2,
+ 0x88, 0x92, 0x01, 0x3D, 0x01, 0x28, 0x01, 0x29,
+ 0x01, 0x6E, 0x02, 0x52, 0x73, 0x03, 0x61, 0x2F,
+ 0x63, 0x03, 0x61, 0x2F, 0x73, 0x01, 0x43, 0x03,
+ 0xC2, 0xB0, 0x43, 0x03, 0x63, 0x2F, 0x6F, 0x03,
+ 0x63, 0x2F, 0x75, 0x02, 0xC6, 0x90, 0x03, 0xC2,
+ // Bytes 14c0 - 14ff
+ 0xB0, 0x46, 0x02, 0xC4, 0xA7, 0x02, 0x4E, 0x6F,
+ 0x01, 0x51, 0x02, 0x53, 0x4D, 0x03, 0x54, 0x45,
+ 0x4C, 0x02, 0x54, 0x4D, 0x01, 0x5A, 0x02, 0xCE,
+ 0xA9, 0x01, 0x46, 0x02, 0xD7, 0x90, 0x02, 0xD7,
+ 0x91, 0x02, 0xD7, 0x92, 0x02, 0xD7, 0x93, 0x03,
+ 0x46, 0x41, 0x58, 0x02, 0xCE, 0x93, 0x02, 0xCE,
+ 0xA0, 0x03, 0xE2, 0x88, 0x91, 0x05, 0x31, 0xE2,
+ 0x81, 0x84, 0x37, 0x05, 0x31, 0xE2, 0x81, 0x84,
+ // Bytes 1500 - 153f
+ 0x39, 0x06, 0x31, 0xE2, 0x81, 0x84, 0x31, 0x30,
+ 0x05, 0x31, 0xE2, 0x81, 0x84, 0x33, 0x05, 0x32,
+ 0xE2, 0x81, 0x84, 0x33, 0x05, 0x31, 0xE2, 0x81,
+ 0x84, 0x35, 0x05, 0x32, 0xE2, 0x81, 0x84, 0x35,
+ 0x05, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x05, 0x34,
+ 0xE2, 0x81, 0x84, 0x35, 0x05, 0x31, 0xE2, 0x81,
+ 0x84, 0x36, 0x05, 0x35, 0xE2, 0x81, 0x84, 0x36,
+ 0x05, 0x31, 0xE2, 0x81, 0x84, 0x38, 0x05, 0x33,
+ // Bytes 1540 - 157f
+ 0xE2, 0x81, 0x84, 0x38, 0x05, 0x35, 0xE2, 0x81,
+ 0x84, 0x38, 0x05, 0x37, 0xE2, 0x81, 0x84, 0x38,
+ 0x04, 0x31, 0xE2, 0x81, 0x84, 0x02, 0x49, 0x49,
+ 0x03, 0x49, 0x49, 0x49, 0x02, 0x49, 0x56, 0x01,
+ 0x56, 0x02, 0x56, 0x49, 0x03, 0x56, 0x49, 0x49,
+ 0x04, 0x56, 0x49, 0x49, 0x49, 0x02, 0x49, 0x58,
+ 0x01, 0x58, 0x02, 0x58, 0x49, 0x03, 0x58, 0x49,
+ 0x49, 0x02, 0x69, 0x69, 0x03, 0x69, 0x69, 0x69,
+ // Bytes 1580 - 15bf
+ 0x02, 0x69, 0x76, 0x02, 0x76, 0x69, 0x03, 0x76,
+ 0x69, 0x69, 0x04, 0x76, 0x69, 0x69, 0x69, 0x02,
+ 0x69, 0x78, 0x02, 0x78, 0x69, 0x03, 0x78, 0x69,
+ 0x69, 0x05, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x05,
+ 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05, 0xE2, 0x86,
+ 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x86, 0x94, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x87, 0x90, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x87, 0x94, 0xCC, 0xB8, 0x05, 0xE2, 0x87,
+ // Bytes 15c0 - 15ff
+ 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x88, 0x83, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05, 0xE2, 0x88,
+ 0xA3, 0xCC, 0xB8, 0x05, 0xE2, 0x88, 0xA5, 0xCC,
+ 0xB8, 0x06, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB,
+ 0x09, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2,
+ 0x88, 0xAB, 0x06, 0xE2, 0x88, 0xAE, 0xE2, 0x88,
+ 0xAE, 0x09, 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE,
+ // Bytes 1600 - 163f
+ 0xE2, 0x88, 0xAE, 0x05, 0xE2, 0x88, 0xBC, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x89, 0x83, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x89, 0x85, 0xCC, 0xB8, 0x05, 0xE2, 0x89,
+ 0x88, 0xCC, 0xB8, 0x03, 0x3D, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05, 0xE2, 0x89,
+ 0x8D, 0xCC, 0xB8, 0x03, 0x3C, 0xCC, 0xB8, 0x03,
+ 0x3E, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xA4, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05,
+ // Bytes 1640 - 167f
+ 0xE2, 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0xE2, 0x89,
+ 0xB3, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xB6, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x89, 0xB7, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x89, 0xBA, 0xCC, 0xB8, 0x05, 0xE2, 0x89,
+ 0xBB, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0x82, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x8A, 0x83, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x8A, 0x86, 0xCC, 0xB8, 0x05, 0xE2, 0x8A,
+ 0x87, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0xA2, 0xCC,
+ // Bytes 1680 - 16bf
+ 0xB8, 0x05, 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0xE2, 0x8A,
+ 0xAB, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xBC, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x8A, 0x91, 0xCC, 0xB8, 0x05, 0xE2, 0x8A,
+ 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0xB2, 0xCC,
+ 0xB8, 0x05, 0xE2, 0x8A, 0xB3, 0xCC, 0xB8, 0x05,
+ 0xE2, 0x8A, 0xB4, 0xCC, 0xB8, 0x05, 0xE2, 0x8A,
+ // Bytes 16c0 - 16ff
+ 0xB5, 0xCC, 0xB8, 0x03, 0xE3, 0x80, 0x88, 0x03,
+ 0xE3, 0x80, 0x89, 0x02, 0x31, 0x30, 0x02, 0x31,
+ 0x31, 0x02, 0x31, 0x32, 0x02, 0x31, 0x33, 0x02,
+ 0x31, 0x34, 0x02, 0x31, 0x35, 0x02, 0x31, 0x36,
+ 0x02, 0x31, 0x37, 0x02, 0x31, 0x38, 0x02, 0x31,
+ 0x39, 0x02, 0x32, 0x30, 0x03, 0x28, 0x31, 0x29,
+ 0x03, 0x28, 0x32, 0x29, 0x03, 0x28, 0x33, 0x29,
+ 0x03, 0x28, 0x34, 0x29, 0x03, 0x28, 0x35, 0x29,
+ // Bytes 1700 - 173f
+ 0x03, 0x28, 0x36, 0x29, 0x03, 0x28, 0x37, 0x29,
+ 0x03, 0x28, 0x38, 0x29, 0x03, 0x28, 0x39, 0x29,
+ 0x04, 0x28, 0x31, 0x30, 0x29, 0x04, 0x28, 0x31,
+ 0x31, 0x29, 0x04, 0x28, 0x31, 0x32, 0x29, 0x04,
+ 0x28, 0x31, 0x33, 0x29, 0x04, 0x28, 0x31, 0x34,
+ 0x29, 0x04, 0x28, 0x31, 0x35, 0x29, 0x04, 0x28,
+ 0x31, 0x36, 0x29, 0x04, 0x28, 0x31, 0x37, 0x29,
+ 0x04, 0x28, 0x31, 0x38, 0x29, 0x04, 0x28, 0x31,
+ // Bytes 1740 - 177f
+ 0x39, 0x29, 0x04, 0x28, 0x32, 0x30, 0x29, 0x02,
+ 0x31, 0x2E, 0x02, 0x32, 0x2E, 0x02, 0x33, 0x2E,
+ 0x02, 0x34, 0x2E, 0x02, 0x35, 0x2E, 0x02, 0x36,
+ 0x2E, 0x02, 0x37, 0x2E, 0x02, 0x38, 0x2E, 0x02,
+ 0x39, 0x2E, 0x03, 0x31, 0x30, 0x2E, 0x03, 0x31,
+ 0x31, 0x2E, 0x03, 0x31, 0x32, 0x2E, 0x03, 0x31,
+ 0x33, 0x2E, 0x03, 0x31, 0x34, 0x2E, 0x03, 0x31,
+ 0x35, 0x2E, 0x03, 0x31, 0x36, 0x2E, 0x03, 0x31,
+ // Bytes 1780 - 17bf
+ 0x37, 0x2E, 0x03, 0x31, 0x38, 0x2E, 0x03, 0x31,
+ 0x39, 0x2E, 0x03, 0x32, 0x30, 0x2E, 0x03, 0x28,
+ 0x61, 0x29, 0x03, 0x28, 0x62, 0x29, 0x03, 0x28,
+ 0x63, 0x29, 0x03, 0x28, 0x64, 0x29, 0x03, 0x28,
+ 0x65, 0x29, 0x03, 0x28, 0x66, 0x29, 0x03, 0x28,
+ 0x67, 0x29, 0x03, 0x28, 0x68, 0x29, 0x03, 0x28,
+ 0x69, 0x29, 0x03, 0x28, 0x6A, 0x29, 0x03, 0x28,
+ 0x6B, 0x29, 0x03, 0x28, 0x6C, 0x29, 0x03, 0x28,
+ // Bytes 17c0 - 17ff
+ 0x6D, 0x29, 0x03, 0x28, 0x6E, 0x29, 0x03, 0x28,
+ 0x6F, 0x29, 0x03, 0x28, 0x70, 0x29, 0x03, 0x28,
+ 0x71, 0x29, 0x03, 0x28, 0x72, 0x29, 0x03, 0x28,
+ 0x73, 0x29, 0x03, 0x28, 0x74, 0x29, 0x03, 0x28,
+ 0x75, 0x29, 0x03, 0x28, 0x76, 0x29, 0x03, 0x28,
+ 0x77, 0x29, 0x03, 0x28, 0x78, 0x29, 0x03, 0x28,
+ 0x79, 0x29, 0x03, 0x28, 0x7A, 0x29, 0x01, 0x53,
+ 0x01, 0x59, 0x01, 0x71, 0x0C, 0xE2, 0x88, 0xAB,
+ // Bytes 1800 - 183f
+ 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88,
+ 0xAB, 0x03, 0x3A, 0x3A, 0x3D, 0x02, 0x3D, 0x3D,
+ 0x03, 0x3D, 0x3D, 0x3D, 0x05, 0xE2, 0xAB, 0x9D,
+ 0xCC, 0xB8, 0x03, 0xE2, 0xB5, 0xA1, 0x03, 0xE6,
+ 0xAF, 0x8D, 0x03, 0xE9, 0xBE, 0x9F, 0x03, 0xE4,
+ 0xB8, 0x80, 0x03, 0xE4, 0xB8, 0xA8, 0x03, 0xE4,
+ 0xB8, 0xB6, 0x03, 0xE4, 0xB8, 0xBF, 0x03, 0xE4,
+ 0xB9, 0x99, 0x03, 0xE4, 0xBA, 0x85, 0x03, 0xE4,
+ // Bytes 1840 - 187f
+ 0xBA, 0x8C, 0x03, 0xE4, 0xBA, 0xA0, 0x03, 0xE4,
+ 0xBA, 0xBA, 0x03, 0xE5, 0x84, 0xBF, 0x03, 0xE5,
+ 0x85, 0xA5, 0x03, 0xE5, 0x85, 0xAB, 0x03, 0xE5,
+ 0x86, 0x82, 0x03, 0xE5, 0x86, 0x96, 0x03, 0xE5,
+ 0x86, 0xAB, 0x03, 0xE5, 0x87, 0xA0, 0x03, 0xE5,
+ 0x87, 0xB5, 0x03, 0xE5, 0x88, 0x80, 0x03, 0xE5,
+ 0x8A, 0x9B, 0x03, 0xE5, 0x8B, 0xB9, 0x03, 0xE5,
+ 0x8C, 0x95, 0x03, 0xE5, 0x8C, 0x9A, 0x03, 0xE5,
+ // Bytes 1880 - 18bf
+ 0x8C, 0xB8, 0x03, 0xE5, 0x8D, 0x81, 0x03, 0xE5,
+ 0x8D, 0x9C, 0x03, 0xE5, 0x8D, 0xA9, 0x03, 0xE5,
+ 0x8E, 0x82, 0x03, 0xE5, 0x8E, 0xB6, 0x03, 0xE5,
+ 0x8F, 0x88, 0x03, 0xE5, 0x8F, 0xA3, 0x03, 0xE5,
+ 0x9B, 0x97, 0x03, 0xE5, 0x9C, 0x9F, 0x03, 0xE5,
+ 0xA3, 0xAB, 0x03, 0xE5, 0xA4, 0x82, 0x03, 0xE5,
+ 0xA4, 0x8A, 0x03, 0xE5, 0xA4, 0x95, 0x03, 0xE5,
+ 0xA4, 0xA7, 0x03, 0xE5, 0xA5, 0xB3, 0x03, 0xE5,
+ // Bytes 18c0 - 18ff
+ 0xAD, 0x90, 0x03, 0xE5, 0xAE, 0x80, 0x03, 0xE5,
+ 0xAF, 0xB8, 0x03, 0xE5, 0xB0, 0x8F, 0x03, 0xE5,
+ 0xB0, 0xA2, 0x03, 0xE5, 0xB0, 0xB8, 0x03, 0xE5,
+ 0xB1, 0xAE, 0x03, 0xE5, 0xB1, 0xB1, 0x03, 0xE5,
+ 0xB7, 0x9B, 0x03, 0xE5, 0xB7, 0xA5, 0x03, 0xE5,
+ 0xB7, 0xB1, 0x03, 0xE5, 0xB7, 0xBE, 0x03, 0xE5,
+ 0xB9, 0xB2, 0x03, 0xE5, 0xB9, 0xBA, 0x03, 0xE5,
+ 0xB9, 0xBF, 0x03, 0xE5, 0xBB, 0xB4, 0x03, 0xE5,
+ // Bytes 1900 - 193f
+ 0xBB, 0xBE, 0x03, 0xE5, 0xBC, 0x8B, 0x03, 0xE5,
+ 0xBC, 0x93, 0x03, 0xE5, 0xBD, 0x90, 0x03, 0xE5,
+ 0xBD, 0xA1, 0x03, 0xE5, 0xBD, 0xB3, 0x03, 0xE5,
+ 0xBF, 0x83, 0x03, 0xE6, 0x88, 0x88, 0x03, 0xE6,
+ 0x88, 0xB6, 0x03, 0xE6, 0x89, 0x8B, 0x03, 0xE6,
+ 0x94, 0xAF, 0x03, 0xE6, 0x94, 0xB4, 0x03, 0xE6,
+ 0x96, 0x87, 0x03, 0xE6, 0x96, 0x97, 0x03, 0xE6,
+ 0x96, 0xA4, 0x03, 0xE6, 0x96, 0xB9, 0x03, 0xE6,
+ // Bytes 1940 - 197f
+ 0x97, 0xA0, 0x03, 0xE6, 0x97, 0xA5, 0x03, 0xE6,
+ 0x9B, 0xB0, 0x03, 0xE6, 0x9C, 0x88, 0x03, 0xE6,
+ 0x9C, 0xA8, 0x03, 0xE6, 0xAC, 0xA0, 0x03, 0xE6,
+ 0xAD, 0xA2, 0x03, 0xE6, 0xAD, 0xB9, 0x03, 0xE6,
+ 0xAE, 0xB3, 0x03, 0xE6, 0xAF, 0x8B, 0x03, 0xE6,
+ 0xAF, 0x94, 0x03, 0xE6, 0xAF, 0x9B, 0x03, 0xE6,
+ 0xB0, 0x8F, 0x03, 0xE6, 0xB0, 0x94, 0x03, 0xE6,
+ 0xB0, 0xB4, 0x03, 0xE7, 0x81, 0xAB, 0x03, 0xE7,
+ // Bytes 1980 - 19bf
+ 0x88, 0xAA, 0x03, 0xE7, 0x88, 0xB6, 0x03, 0xE7,
+ 0x88, 0xBB, 0x03, 0xE7, 0x88, 0xBF, 0x03, 0xE7,
+ 0x89, 0x87, 0x03, 0xE7, 0x89, 0x99, 0x03, 0xE7,
+ 0x89, 0x9B, 0x03, 0xE7, 0x8A, 0xAC, 0x03, 0xE7,
+ 0x8E, 0x84, 0x03, 0xE7, 0x8E, 0x89, 0x03, 0xE7,
+ 0x93, 0x9C, 0x03, 0xE7, 0x93, 0xA6, 0x03, 0xE7,
+ 0x94, 0x98, 0x03, 0xE7, 0x94, 0x9F, 0x03, 0xE7,
+ 0x94, 0xA8, 0x03, 0xE7, 0x94, 0xB0, 0x03, 0xE7,
+ // Bytes 19c0 - 19ff
+ 0x96, 0x8B, 0x03, 0xE7, 0x96, 0x92, 0x03, 0xE7,
+ 0x99, 0xB6, 0x03, 0xE7, 0x99, 0xBD, 0x03, 0xE7,
+ 0x9A, 0xAE, 0x03, 0xE7, 0x9A, 0xBF, 0x03, 0xE7,
+ 0x9B, 0xAE, 0x03, 0xE7, 0x9F, 0x9B, 0x03, 0xE7,
+ 0x9F, 0xA2, 0x03, 0xE7, 0x9F, 0xB3, 0x03, 0xE7,
+ 0xA4, 0xBA, 0x03, 0xE7, 0xA6, 0xB8, 0x03, 0xE7,
+ 0xA6, 0xBE, 0x03, 0xE7, 0xA9, 0xB4, 0x03, 0xE7,
+ 0xAB, 0x8B, 0x03, 0xE7, 0xAB, 0xB9, 0x03, 0xE7,
+ // Bytes 1a00 - 1a3f
+ 0xB1, 0xB3, 0x03, 0xE7, 0xB3, 0xB8, 0x03, 0xE7,
+ 0xBC, 0xB6, 0x03, 0xE7, 0xBD, 0x91, 0x03, 0xE7,
+ 0xBE, 0x8A, 0x03, 0xE7, 0xBE, 0xBD, 0x03, 0xE8,
+ 0x80, 0x81, 0x03, 0xE8, 0x80, 0x8C, 0x03, 0xE8,
+ 0x80, 0x92, 0x03, 0xE8, 0x80, 0xB3, 0x03, 0xE8,
+ 0x81, 0xBF, 0x03, 0xE8, 0x82, 0x89, 0x03, 0xE8,
+ 0x87, 0xA3, 0x03, 0xE8, 0x87, 0xAA, 0x03, 0xE8,
+ 0x87, 0xB3, 0x03, 0xE8, 0x87, 0xBC, 0x03, 0xE8,
+ // Bytes 1a40 - 1a7f
+ 0x88, 0x8C, 0x03, 0xE8, 0x88, 0x9B, 0x03, 0xE8,
+ 0x88, 0x9F, 0x03, 0xE8, 0x89, 0xAE, 0x03, 0xE8,
+ 0x89, 0xB2, 0x03, 0xE8, 0x89, 0xB8, 0x03, 0xE8,
+ 0x99, 0x8D, 0x03, 0xE8, 0x99, 0xAB, 0x03, 0xE8,
+ 0xA1, 0x80, 0x03, 0xE8, 0xA1, 0x8C, 0x03, 0xE8,
+ 0xA1, 0xA3, 0x03, 0xE8, 0xA5, 0xBE, 0x03, 0xE8,
+ 0xA6, 0x8B, 0x03, 0xE8, 0xA7, 0x92, 0x03, 0xE8,
+ 0xA8, 0x80, 0x03, 0xE8, 0xB0, 0xB7, 0x03, 0xE8,
+ // Bytes 1a80 - 1abf
+ 0xB1, 0x86, 0x03, 0xE8, 0xB1, 0x95, 0x03, 0xE8,
+ 0xB1, 0xB8, 0x03, 0xE8, 0xB2, 0x9D, 0x03, 0xE8,
+ 0xB5, 0xA4, 0x03, 0xE8, 0xB5, 0xB0, 0x03, 0xE8,
+ 0xB6, 0xB3, 0x03, 0xE8, 0xBA, 0xAB, 0x03, 0xE8,
+ 0xBB, 0x8A, 0x03, 0xE8, 0xBE, 0x9B, 0x03, 0xE8,
+ 0xBE, 0xB0, 0x03, 0xE8, 0xBE, 0xB5, 0x03, 0xE9,
+ 0x82, 0x91, 0x03, 0xE9, 0x85, 0x89, 0x03, 0xE9,
+ 0x87, 0x86, 0x03, 0xE9, 0x87, 0x8C, 0x03, 0xE9,
+ // Bytes 1ac0 - 1aff
+ 0x87, 0x91, 0x03, 0xE9, 0x95, 0xB7, 0x03, 0xE9,
+ 0x96, 0x80, 0x03, 0xE9, 0x98, 0x9C, 0x03, 0xE9,
+ 0x9A, 0xB6, 0x03, 0xE9, 0x9A, 0xB9, 0x03, 0xE9,
+ 0x9B, 0xA8, 0x03, 0xE9, 0x9D, 0x91, 0x03, 0xE9,
+ 0x9D, 0x9E, 0x03, 0xE9, 0x9D, 0xA2, 0x03, 0xE9,
+ 0x9D, 0xA9, 0x03, 0xE9, 0x9F, 0x8B, 0x03, 0xE9,
+ 0x9F, 0xAD, 0x03, 0xE9, 0x9F, 0xB3, 0x03, 0xE9,
+ 0xA0, 0x81, 0x03, 0xE9, 0xA2, 0xA8, 0x03, 0xE9,
+ // Bytes 1b00 - 1b3f
+ 0xA3, 0x9B, 0x03, 0xE9, 0xA3, 0x9F, 0x03, 0xE9,
+ 0xA6, 0x96, 0x03, 0xE9, 0xA6, 0x99, 0x03, 0xE9,
+ 0xA6, 0xAC, 0x03, 0xE9, 0xAA, 0xA8, 0x03, 0xE9,
+ 0xAB, 0x98, 0x03, 0xE9, 0xAB, 0x9F, 0x03, 0xE9,
+ 0xAC, 0xA5, 0x03, 0xE9, 0xAC, 0xAF, 0x03, 0xE9,
+ 0xAC, 0xB2, 0x03, 0xE9, 0xAC, 0xBC, 0x03, 0xE9,
+ 0xAD, 0x9A, 0x03, 0xE9, 0xB3, 0xA5, 0x03, 0xE9,
+ 0xB9, 0xB5, 0x03, 0xE9, 0xB9, 0xBF, 0x03, 0xE9,
+ // Bytes 1b40 - 1b7f
+ 0xBA, 0xA5, 0x03, 0xE9, 0xBA, 0xBB, 0x03, 0xE9,
+ 0xBB, 0x83, 0x03, 0xE9, 0xBB, 0x8D, 0x03, 0xE9,
+ 0xBB, 0x91, 0x03, 0xE9, 0xBB, 0xB9, 0x03, 0xE9,
+ 0xBB, 0xBD, 0x03, 0xE9, 0xBC, 0x8E, 0x03, 0xE9,
+ 0xBC, 0x93, 0x03, 0xE9, 0xBC, 0xA0, 0x03, 0xE9,
+ 0xBC, 0xBB, 0x03, 0xE9, 0xBD, 0x8A, 0x03, 0xE9,
+ 0xBD, 0x92, 0x03, 0xE9, 0xBE, 0x8D, 0x03, 0xE9,
+ 0xBE, 0x9C, 0x03, 0xE9, 0xBE, 0xA0, 0x03, 0xE3,
+ // Bytes 1b80 - 1bbf
+ 0x80, 0x92, 0x03, 0xE5, 0x8D, 0x84, 0x03, 0xE5,
+ 0x8D, 0x85, 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x06,
+ 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x81, 0x93, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81,
+ 0x95, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0x97,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0x99, 0xE3,
+ // Bytes 1bc0 - 1bff
+ 0x82, 0x99, 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x06,
+ 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81,
+ 0xA6, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xA8,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xAF, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82,
+ // Bytes 1c00 - 1c3f
+ 0x9A, 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x06,
+ 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x81,
+ 0xB8, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xB8,
+ 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x81, 0xBB, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82,
+ 0x9A, 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99,
+ // Bytes 1c40 - 1c7f
+ 0x04, 0x20, 0xE3, 0x82, 0x99, 0x04, 0x20, 0xE3,
+ 0x82, 0x9A, 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x82, 0x88, 0xE3, 0x82, 0x8A,
+ 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x06,
+ 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82,
+ 0xB1, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB3,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB5, 0xE3,
+ // Bytes 1c80 - 1cbf
+ 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x06,
+ 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83,
+ 0x81, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x84,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x86, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82,
+ // Bytes 1cc0 - 1cff
+ 0x99, 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99,
+ 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x06,
+ 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x83,
+ 0x95, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x95,
+ 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x83, 0x98, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+ 0x9A, 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99,
+ // Bytes 1d00 - 1d3f
+ 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x06,
+ 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x06, 0xE3,
+ 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83,
+ 0xB0, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0xB1,
+ 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0xB2, 0xE3,
+ 0x82, 0x99, 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82,
+ 0x99, 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88,
+ 0x03, 0xE1, 0x84, 0x80, 0x03, 0xE1, 0x84, 0x81,
+ // Bytes 1d40 - 1d7f
+ 0x03, 0xE1, 0x86, 0xAA, 0x03, 0xE1, 0x84, 0x82,
+ 0x03, 0xE1, 0x86, 0xAC, 0x03, 0xE1, 0x86, 0xAD,
+ 0x03, 0xE1, 0x84, 0x83, 0x03, 0xE1, 0x84, 0x84,
+ 0x03, 0xE1, 0x84, 0x85, 0x03, 0xE1, 0x86, 0xB0,
+ 0x03, 0xE1, 0x86, 0xB1, 0x03, 0xE1, 0x86, 0xB2,
+ 0x03, 0xE1, 0x86, 0xB3, 0x03, 0xE1, 0x86, 0xB4,
+ 0x03, 0xE1, 0x86, 0xB5, 0x03, 0xE1, 0x84, 0x9A,
+ 0x03, 0xE1, 0x84, 0x86, 0x03, 0xE1, 0x84, 0x87,
+ // Bytes 1d80 - 1dbf
+ 0x03, 0xE1, 0x84, 0x88, 0x03, 0xE1, 0x84, 0xA1,
+ 0x03, 0xE1, 0x84, 0x89, 0x03, 0xE1, 0x84, 0x8A,
+ 0x03, 0xE1, 0x84, 0x8B, 0x03, 0xE1, 0x84, 0x8C,
+ 0x03, 0xE1, 0x84, 0x8D, 0x03, 0xE1, 0x84, 0x8E,
+ 0x03, 0xE1, 0x84, 0x8F, 0x03, 0xE1, 0x84, 0x90,
+ 0x03, 0xE1, 0x84, 0x91, 0x03, 0xE1, 0x84, 0x92,
+ 0x03, 0xE1, 0x85, 0xA1, 0x03, 0xE1, 0x85, 0xA2,
+ 0x03, 0xE1, 0x85, 0xA3, 0x03, 0xE1, 0x85, 0xA4,
+ // Bytes 1dc0 - 1dff
+ 0x03, 0xE1, 0x85, 0xA5, 0x03, 0xE1, 0x85, 0xA6,
+ 0x03, 0xE1, 0x85, 0xA7, 0x03, 0xE1, 0x85, 0xA8,
+ 0x03, 0xE1, 0x85, 0xA9, 0x03, 0xE1, 0x85, 0xAA,
+ 0x03, 0xE1, 0x85, 0xAB, 0x03, 0xE1, 0x85, 0xAC,
+ 0x03, 0xE1, 0x85, 0xAD, 0x03, 0xE1, 0x85, 0xAE,
+ 0x03, 0xE1, 0x85, 0xAF, 0x03, 0xE1, 0x85, 0xB0,
+ 0x03, 0xE1, 0x85, 0xB1, 0x03, 0xE1, 0x85, 0xB2,
+ 0x03, 0xE1, 0x85, 0xB3, 0x03, 0xE1, 0x85, 0xB4,
+ // Bytes 1e00 - 1e3f
+ 0x03, 0xE1, 0x85, 0xB5, 0x03, 0xE1, 0x85, 0xA0,
+ 0x03, 0xE1, 0x84, 0x94, 0x03, 0xE1, 0x84, 0x95,
+ 0x03, 0xE1, 0x87, 0x87, 0x03, 0xE1, 0x87, 0x88,
+ 0x03, 0xE1, 0x87, 0x8C, 0x03, 0xE1, 0x87, 0x8E,
+ 0x03, 0xE1, 0x87, 0x93, 0x03, 0xE1, 0x87, 0x97,
+ 0x03, 0xE1, 0x87, 0x99, 0x03, 0xE1, 0x84, 0x9C,
+ 0x03, 0xE1, 0x87, 0x9D, 0x03, 0xE1, 0x87, 0x9F,
+ 0x03, 0xE1, 0x84, 0x9D, 0x03, 0xE1, 0x84, 0x9E,
+ // Bytes 1e40 - 1e7f
+ 0x03, 0xE1, 0x84, 0xA0, 0x03, 0xE1, 0x84, 0xA2,
+ 0x03, 0xE1, 0x84, 0xA3, 0x03, 0xE1, 0x84, 0xA7,
+ 0x03, 0xE1, 0x84, 0xA9, 0x03, 0xE1, 0x84, 0xAB,
+ 0x03, 0xE1, 0x84, 0xAC, 0x03, 0xE1, 0x84, 0xAD,
+ 0x03, 0xE1, 0x84, 0xAE, 0x03, 0xE1, 0x84, 0xAF,
+ 0x03, 0xE1, 0x84, 0xB2, 0x03, 0xE1, 0x84, 0xB6,
+ 0x03, 0xE1, 0x85, 0x80, 0x03, 0xE1, 0x85, 0x87,
+ 0x03, 0xE1, 0x85, 0x8C, 0x03, 0xE1, 0x87, 0xB1,
+ // Bytes 1e80 - 1ebf
+ 0x03, 0xE1, 0x87, 0xB2, 0x03, 0xE1, 0x85, 0x97,
+ 0x03, 0xE1, 0x85, 0x98, 0x03, 0xE1, 0x85, 0x99,
+ 0x03, 0xE1, 0x86, 0x84, 0x03, 0xE1, 0x86, 0x85,
+ 0x03, 0xE1, 0x86, 0x88, 0x03, 0xE1, 0x86, 0x91,
+ 0x03, 0xE1, 0x86, 0x92, 0x03, 0xE1, 0x86, 0x94,
+ 0x03, 0xE1, 0x86, 0x9E, 0x03, 0xE1, 0x86, 0xA1,
+ 0x03, 0xE4, 0xB8, 0x89, 0x03, 0xE5, 0x9B, 0x9B,
+ 0x03, 0xE4, 0xB8, 0x8A, 0x03, 0xE4, 0xB8, 0xAD,
+ // Bytes 1ec0 - 1eff
+ 0x03, 0xE4, 0xB8, 0x8B, 0x03, 0xE7, 0x94, 0xB2,
+ 0x03, 0xE4, 0xB8, 0x99, 0x03, 0xE4, 0xB8, 0x81,
+ 0x03, 0xE5, 0xA4, 0xA9, 0x03, 0xE5, 0x9C, 0xB0,
+ 0x05, 0x28, 0xE1, 0x84, 0x80, 0x29, 0x05, 0x28,
+ 0xE1, 0x84, 0x82, 0x29, 0x05, 0x28, 0xE1, 0x84,
+ 0x83, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x85, 0x29,
+ 0x05, 0x28, 0xE1, 0x84, 0x86, 0x29, 0x05, 0x28,
+ 0xE1, 0x84, 0x87, 0x29, 0x05, 0x28, 0xE1, 0x84,
+ // Bytes 1f00 - 1f3f
+ 0x89, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x8B, 0x29,
+ 0x05, 0x28, 0xE1, 0x84, 0x8C, 0x29, 0x05, 0x28,
+ 0xE1, 0x84, 0x8E, 0x29, 0x05, 0x28, 0xE1, 0x84,
+ 0x8F, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x90, 0x29,
+ 0x05, 0x28, 0xE1, 0x84, 0x91, 0x29, 0x05, 0x28,
+ 0xE1, 0x84, 0x92, 0x29, 0x08, 0x28, 0xE1, 0x84,
+ 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1,
+ 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28,
+ // Bytes 1f40 - 1f7f
+ 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x29, 0x08,
+ 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x29,
+ 0x08, 0x28, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1,
+ 0x29, 0x08, 0x28, 0xE1, 0x84, 0x87, 0xE1, 0x85,
+ 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x89, 0xE1,
+ 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x8B,
+ 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84,
+ 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1,
+ // Bytes 1f80 - 1fbf
+ 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28,
+ 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x29, 0x08,
+ 0x28, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x29,
+ 0x08, 0x28, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1,
+ 0x29, 0x08, 0x28, 0xE1, 0x84, 0x92, 0xE1, 0x85,
+ 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x8C, 0xE1,
+ 0x85, 0xAE, 0x29, 0x11, 0x28, 0xE1, 0x84, 0x8B,
+ 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1, 0x85,
+ // Bytes 1fc0 - 1fff
+ 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x0E, 0x28, 0xE1,
+ 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92,
+ 0xE1, 0x85, 0xAE, 0x29, 0x05, 0x28, 0xE4, 0xB8,
+ 0x80, 0x29, 0x05, 0x28, 0xE4, 0xBA, 0x8C, 0x29,
+ 0x05, 0x28, 0xE4, 0xB8, 0x89, 0x29, 0x05, 0x28,
+ 0xE5, 0x9B, 0x9B, 0x29, 0x05, 0x28, 0xE4, 0xBA,
+ 0x94, 0x29, 0x05, 0x28, 0xE5, 0x85, 0xAD, 0x29,
+ 0x05, 0x28, 0xE4, 0xB8, 0x83, 0x29, 0x05, 0x28,
+ // Bytes 2000 - 203f
+ 0xE5, 0x85, 0xAB, 0x29, 0x05, 0x28, 0xE4, 0xB9,
+ 0x9D, 0x29, 0x05, 0x28, 0xE5, 0x8D, 0x81, 0x29,
+ 0x05, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x05, 0x28,
+ 0xE7, 0x81, 0xAB, 0x29, 0x05, 0x28, 0xE6, 0xB0,
+ 0xB4, 0x29, 0x05, 0x28, 0xE6, 0x9C, 0xA8, 0x29,
+ 0x05, 0x28, 0xE9, 0x87, 0x91, 0x29, 0x05, 0x28,
+ 0xE5, 0x9C, 0x9F, 0x29, 0x05, 0x28, 0xE6, 0x97,
+ 0xA5, 0x29, 0x05, 0x28, 0xE6, 0xA0, 0xAA, 0x29,
+ // Bytes 2040 - 207f
+ 0x05, 0x28, 0xE6, 0x9C, 0x89, 0x29, 0x05, 0x28,
+ 0xE7, 0xA4, 0xBE, 0x29, 0x05, 0x28, 0xE5, 0x90,
+ 0x8D, 0x29, 0x05, 0x28, 0xE7, 0x89, 0xB9, 0x29,
+ 0x05, 0x28, 0xE8, 0xB2, 0xA1, 0x29, 0x05, 0x28,
+ 0xE7, 0xA5, 0x9D, 0x29, 0x05, 0x28, 0xE5, 0x8A,
+ 0xB4, 0x29, 0x05, 0x28, 0xE4, 0xBB, 0xA3, 0x29,
+ 0x05, 0x28, 0xE5, 0x91, 0xBC, 0x29, 0x05, 0x28,
+ 0xE5, 0xAD, 0xA6, 0x29, 0x05, 0x28, 0xE7, 0x9B,
+ // Bytes 2080 - 20bf
+ 0xA3, 0x29, 0x05, 0x28, 0xE4, 0xBC, 0x81, 0x29,
+ 0x05, 0x28, 0xE8, 0xB3, 0x87, 0x29, 0x05, 0x28,
+ 0xE5, 0x8D, 0x94, 0x29, 0x05, 0x28, 0xE7, 0xA5,
+ 0xAD, 0x29, 0x05, 0x28, 0xE4, 0xBC, 0x91, 0x29,
+ 0x05, 0x28, 0xE8, 0x87, 0xAA, 0x29, 0x05, 0x28,
+ 0xE8, 0x87, 0xB3, 0x29, 0x03, 0xE5, 0x95, 0x8F,
+ 0x03, 0xE5, 0xB9, 0xBC, 0x03, 0xE7, 0xAE, 0x8F,
+ 0x03, 0x50, 0x54, 0x45, 0x02, 0x32, 0x31, 0x02,
+ // Bytes 20c0 - 20ff
+ 0x32, 0x32, 0x02, 0x32, 0x33, 0x02, 0x32, 0x34,
+ 0x02, 0x32, 0x35, 0x02, 0x32, 0x36, 0x02, 0x32,
+ 0x37, 0x02, 0x32, 0x38, 0x02, 0x32, 0x39, 0x02,
+ 0x33, 0x30, 0x02, 0x33, 0x31, 0x02, 0x33, 0x32,
+ 0x02, 0x33, 0x33, 0x02, 0x33, 0x34, 0x02, 0x33,
+ 0x35, 0x06, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1,
+ 0x06, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x06,
+ 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x06, 0xE1,
+ // Bytes 2100 - 213f
+ 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84,
+ 0x86, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x87,
+ 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x89, 0xE1,
+ 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x8B, 0xE1, 0x85,
+ 0xA1, 0x06, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1,
+ 0x06, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x06,
+ 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x06, 0xE1,
+ 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84,
+ // Bytes 2140 - 217f
+ 0x91, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x92,
+ 0xE1, 0x85, 0xA1, 0x0F, 0xE1, 0x84, 0x8E, 0xE1,
+ 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80,
+ 0xE1, 0x85, 0xA9, 0x0C, 0xE1, 0x84, 0x8C, 0xE1,
+ 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4,
+ 0x06, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x03,
+ 0xE4, 0xBA, 0x94, 0x03, 0xE5, 0x85, 0xAD, 0x03,
+ 0xE4, 0xB8, 0x83, 0x03, 0xE4, 0xB9, 0x9D, 0x03,
+ // Bytes 2180 - 21bf
+ 0xE6, 0xA0, 0xAA, 0x03, 0xE6, 0x9C, 0x89, 0x03,
+ 0xE7, 0xA4, 0xBE, 0x03, 0xE5, 0x90, 0x8D, 0x03,
+ 0xE7, 0x89, 0xB9, 0x03, 0xE8, 0xB2, 0xA1, 0x03,
+ 0xE7, 0xA5, 0x9D, 0x03, 0xE5, 0x8A, 0xB4, 0x03,
+ 0xE7, 0xA7, 0x98, 0x03, 0xE7, 0x94, 0xB7, 0x03,
+ 0xE9, 0x81, 0xA9, 0x03, 0xE5, 0x84, 0xAA, 0x03,
+ 0xE5, 0x8D, 0xB0, 0x03, 0xE6, 0xB3, 0xA8, 0x03,
+ 0xE9, 0xA0, 0x85, 0x03, 0xE4, 0xBC, 0x91, 0x03,
+ // Bytes 21c0 - 21ff
+ 0xE5, 0x86, 0x99, 0x03, 0xE6, 0xAD, 0xA3, 0x03,
+ 0xE5, 0xB7, 0xA6, 0x03, 0xE5, 0x8F, 0xB3, 0x03,
+ 0xE5, 0x8C, 0xBB, 0x03, 0xE5, 0xAE, 0x97, 0x03,
+ 0xE5, 0xAD, 0xA6, 0x03, 0xE7, 0x9B, 0xA3, 0x03,
+ 0xE4, 0xBC, 0x81, 0x03, 0xE8, 0xB3, 0x87, 0x03,
+ 0xE5, 0x8D, 0x94, 0x03, 0xE5, 0xA4, 0x9C, 0x02,
+ 0x33, 0x36, 0x02, 0x33, 0x37, 0x02, 0x33, 0x38,
+ 0x02, 0x33, 0x39, 0x02, 0x34, 0x30, 0x02, 0x34,
+ // Bytes 2200 - 223f
+ 0x31, 0x02, 0x34, 0x32, 0x02, 0x34, 0x33, 0x02,
+ 0x34, 0x34, 0x02, 0x34, 0x35, 0x02, 0x34, 0x36,
+ 0x02, 0x34, 0x37, 0x02, 0x34, 0x38, 0x02, 0x34,
+ 0x39, 0x02, 0x35, 0x30, 0x04, 0x31, 0xE6, 0x9C,
+ 0x88, 0x04, 0x32, 0xE6, 0x9C, 0x88, 0x04, 0x33,
+ 0xE6, 0x9C, 0x88, 0x04, 0x34, 0xE6, 0x9C, 0x88,
+ 0x04, 0x35, 0xE6, 0x9C, 0x88, 0x04, 0x36, 0xE6,
+ 0x9C, 0x88, 0x04, 0x37, 0xE6, 0x9C, 0x88, 0x04,
+ // Bytes 2240 - 227f
+ 0x38, 0xE6, 0x9C, 0x88, 0x04, 0x39, 0xE6, 0x9C,
+ 0x88, 0x05, 0x31, 0x30, 0xE6, 0x9C, 0x88, 0x05,
+ 0x31, 0x31, 0xE6, 0x9C, 0x88, 0x05, 0x31, 0x32,
+ 0xE6, 0x9C, 0x88, 0x02, 0x48, 0x67, 0x03, 0x65,
+ 0x72, 0x67, 0x02, 0x65, 0x56, 0x03, 0x4C, 0x54,
+ 0x44, 0x03, 0xE3, 0x82, 0xA2, 0x03, 0xE3, 0x82,
+ 0xA4, 0x03, 0xE3, 0x82, 0xA6, 0x03, 0xE3, 0x82,
+ 0xA8, 0x03, 0xE3, 0x82, 0xAA, 0x03, 0xE3, 0x82,
+ // Bytes 2280 - 22bf
+ 0xAB, 0x03, 0xE3, 0x82, 0xAD, 0x03, 0xE3, 0x82,
+ 0xAF, 0x03, 0xE3, 0x82, 0xB1, 0x03, 0xE3, 0x82,
+ 0xB3, 0x03, 0xE3, 0x82, 0xB5, 0x03, 0xE3, 0x82,
+ 0xB7, 0x03, 0xE3, 0x82, 0xB9, 0x03, 0xE3, 0x82,
+ 0xBB, 0x03, 0xE3, 0x82, 0xBD, 0x03, 0xE3, 0x82,
+ 0xBF, 0x03, 0xE3, 0x83, 0x81, 0x03, 0xE3, 0x83,
+ 0x84, 0x03, 0xE3, 0x83, 0x86, 0x03, 0xE3, 0x83,
+ 0x88, 0x03, 0xE3, 0x83, 0x8A, 0x03, 0xE3, 0x83,
+ // Bytes 22c0 - 22ff
+ 0x8B, 0x03, 0xE3, 0x83, 0x8C, 0x03, 0xE3, 0x83,
+ 0x8D, 0x03, 0xE3, 0x83, 0x8E, 0x03, 0xE3, 0x83,
+ 0x8F, 0x03, 0xE3, 0x83, 0x92, 0x03, 0xE3, 0x83,
+ 0x95, 0x03, 0xE3, 0x83, 0x98, 0x03, 0xE3, 0x83,
+ 0x9B, 0x03, 0xE3, 0x83, 0x9E, 0x03, 0xE3, 0x83,
+ 0x9F, 0x03, 0xE3, 0x83, 0xA0, 0x03, 0xE3, 0x83,
+ 0xA1, 0x03, 0xE3, 0x83, 0xA2, 0x03, 0xE3, 0x83,
+ 0xA4, 0x03, 0xE3, 0x83, 0xA6, 0x03, 0xE3, 0x83,
+ // Bytes 2300 - 233f
+ 0xA8, 0x03, 0xE3, 0x83, 0xA9, 0x03, 0xE3, 0x83,
+ 0xAA, 0x03, 0xE3, 0x83, 0xAB, 0x03, 0xE3, 0x83,
+ 0xAC, 0x03, 0xE3, 0x83, 0xAD, 0x03, 0xE3, 0x83,
+ 0xAF, 0x03, 0xE3, 0x83, 0xB0, 0x03, 0xE3, 0x83,
+ 0xB1, 0x03, 0xE3, 0x83, 0xB2, 0x0F, 0xE3, 0x82,
+ 0xA2, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3,
+ 0x83, 0xBC, 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82,
+ 0xA2, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x95, 0xE3,
+ // Bytes 2340 - 237f
+ 0x82, 0xA1, 0x0F, 0xE3, 0x82, 0xA2, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
+ 0x82, 0xA2, 0x09, 0xE3, 0x82, 0xA2, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xAB, 0x0F, 0xE3, 0x82, 0xA4,
+ 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
+ 0xAF, 0xE3, 0x82, 0x99, 0x09, 0xE3, 0x82, 0xA4,
+ 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0x09, 0xE3,
+ 0x82, 0xA6, 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3,
+ // Bytes 2380 - 23bf
+ 0x12, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3,
+ 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
+ 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x82, 0xA8, 0xE3,
+ 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xBC,
+ 0x09, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x82, 0xB9, 0x09, 0xE3, 0x82, 0xAA, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xA0, 0x09, 0xE3, 0x82, 0xAB,
+ 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xAA, 0x0C, 0xE3,
+ // Bytes 23c0 - 23ff
+ 0x82, 0xAB, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83,
+ 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82, 0xAB, 0xE3,
+ 0x83, 0xAD, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC,
+ 0x0C, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3,
+ 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x82,
+ 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x83, 0x9E, 0x0C, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
+ 0x99, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0C,
+ // Bytes 2400 - 243f
+ 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0x8B, 0xE3, 0x83, 0xBC, 0x0C, 0xE3, 0x82, 0xAD,
+ 0xE3, 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83,
+ 0xBC, 0x12, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99,
+ 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xBF, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xBC, 0x06, 0xE3, 0x82, 0xAD,
+ 0xE3, 0x83, 0xAD, 0x12, 0xE3, 0x82, 0xAD, 0xE3,
+ 0x83, 0xAD, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
+ // Bytes 2440 - 247f
+ 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x12, 0xE3,
+ 0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1,
+ 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+ 0xAB, 0x0F, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD,
+ 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, 0x83,
+ 0x88, 0x0C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99,
+ 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x12, 0xE3,
+ 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9,
+ // Bytes 2480 - 24bf
+ 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+ 0xB3, 0x12, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB,
+ 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x83, 0xAD, 0x0C, 0xE3, 0x82, 0xAF,
+ 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ 0x8D, 0x09, 0xE3, 0x82, 0xB1, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x82, 0xB9, 0x09, 0xE3, 0x82, 0xB3, 0xE3,
+ 0x83, 0xAB, 0xE3, 0x83, 0x8A, 0x0C, 0xE3, 0x82,
+ // Bytes 24c0 - 24ff
+ 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x9B, 0xE3,
+ 0x82, 0x9A, 0x0C, 0xE3, 0x82, 0xB5, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x0F,
+ 0xE3, 0x82, 0xB5, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+ 0x81, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xA0, 0x0F,
+ 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x09,
+ 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+ // Bytes 2500 - 253f
+ 0x81, 0x09, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3,
+ 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82, 0xBF, 0xE3,
+ 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9,
+ 0x09, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0xE3,
+ 0x82, 0xB7, 0x09, 0xE3, 0x83, 0x88, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAB, 0x06, 0xE3, 0x83, 0x88,
+ 0xE3, 0x83, 0xB3, 0x06, 0xE3, 0x83, 0x8A, 0xE3,
+ 0x83, 0x8E, 0x09, 0xE3, 0x83, 0x8E, 0xE3, 0x83,
+ // Bytes 2540 - 257f
+ 0x83, 0xE3, 0x83, 0x88, 0x09, 0xE3, 0x83, 0x8F,
+ 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0x84, 0x12, 0xE3,
+ 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83,
+ 0x88, 0x0C, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A,
+ 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x84, 0x0F, 0xE3,
+ 0x83, 0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xAB, 0x12, 0xE3,
+ // Bytes 2580 - 25bf
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA2,
+ 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+ 0xAB, 0x0C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x09, 0xE3,
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3,
+ 0x09, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0xE3,
+ 0x83, 0xAB, 0x12, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+ 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3,
+ // Bytes 25c0 - 25ff
+ 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x83,
+ 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0x88, 0x12, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7, 0xE3,
+ 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x09, 0xE3, 0x83,
+ 0x95, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xB3, 0x0F,
+ 0xE3, 0x83, 0x98, 0xE3, 0x82, 0xAF, 0xE3, 0x82,
+ 0xBF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x09,
+ // Bytes 2600 - 263f
+ 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x82,
+ 0xBD, 0x0C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A,
+ 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x09, 0xE3,
+ 0x83, 0x98, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84,
+ 0x0C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
+ 0x83, 0xB3, 0xE3, 0x82, 0xB9, 0x0F, 0xE3, 0x83,
+ 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x83,
+ // Bytes 2640 - 267f
+ 0x98, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x82, 0xBF, 0x0F, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
+ 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x83, 0x88, 0x0C, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x06,
+ 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x0F, 0xE3,
+ 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3,
+ 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x09, 0xE3,
+ // Bytes 2680 - 26bf
+ 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB,
+ 0x09, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xB3, 0x0C, 0xE3, 0x83, 0x9E, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0x09,
+ 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
+ 0xAB, 0x09, 0xE3, 0x83, 0x9E, 0xE3, 0x83, 0x83,
+ 0xE3, 0x83, 0x8F, 0x09, 0xE3, 0x83, 0x9E, 0xE3,
+ 0x83, 0xAB, 0xE3, 0x82, 0xAF, 0x0F, 0xE3, 0x83,
+ // Bytes 26c0 - 26ff
+ 0x9E, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3,
+ 0x83, 0xA7, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x83,
+ 0x9F, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3,
+ 0x83, 0xB3, 0x06, 0xE3, 0x83, 0x9F, 0xE3, 0x83,
+ 0xAA, 0x12, 0xE3, 0x83, 0x9F, 0xE3, 0x83, 0xAA,
+ 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xAB, 0x09, 0xE3, 0x83, 0xA1,
+ 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0F, 0xE3,
+ // Bytes 2700 - 273f
+ 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99,
+ 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x0C, 0xE3,
+ 0x83, 0xA1, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
+ 0xE3, 0x83, 0xAB, 0x0C, 0xE3, 0x83, 0xA4, 0xE3,
+ 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99,
+ 0x09, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xAB, 0x09, 0xE3, 0x83, 0xA6, 0xE3, 0x82,
+ 0xA2, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x83, 0xAA,
+ // Bytes 2740 - 277f
+ 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x83,
+ 0xAB, 0x06, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xA9,
+ 0x0C, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x92, 0xE3,
+ 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0x0F, 0xE3, 0x83,
+ 0xAB, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3,
+ 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x06, 0xE3, 0x83,
+ 0xAC, 0xE3, 0x83, 0xA0, 0x12, 0xE3, 0x83, 0xAC,
+ 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82,
+ // Bytes 2780 - 27bf
+ 0xB1, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3, 0x09,
+ 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, 0x83,
+ 0x88, 0x04, 0x30, 0xE7, 0x82, 0xB9, 0x04, 0x31,
+ 0xE7, 0x82, 0xB9, 0x04, 0x32, 0xE7, 0x82, 0xB9,
+ 0x04, 0x33, 0xE7, 0x82, 0xB9, 0x04, 0x34, 0xE7,
+ 0x82, 0xB9, 0x04, 0x35, 0xE7, 0x82, 0xB9, 0x04,
+ 0x36, 0xE7, 0x82, 0xB9, 0x04, 0x37, 0xE7, 0x82,
+ 0xB9, 0x04, 0x38, 0xE7, 0x82, 0xB9, 0x04, 0x39,
+ // Bytes 27c0 - 27ff
+ 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x30, 0xE7, 0x82,
+ 0xB9, 0x05, 0x31, 0x31, 0xE7, 0x82, 0xB9, 0x05,
+ 0x31, 0x32, 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x33,
+ 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x34, 0xE7, 0x82,
+ 0xB9, 0x05, 0x31, 0x35, 0xE7, 0x82, 0xB9, 0x05,
+ 0x31, 0x36, 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x37,
+ 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x38, 0xE7, 0x82,
+ 0xB9, 0x05, 0x31, 0x39, 0xE7, 0x82, 0xB9, 0x05,
+ // Bytes 2800 - 283f
+ 0x32, 0x30, 0xE7, 0x82, 0xB9, 0x05, 0x32, 0x31,
+ 0xE7, 0x82, 0xB9, 0x05, 0x32, 0x32, 0xE7, 0x82,
+ 0xB9, 0x05, 0x32, 0x33, 0xE7, 0x82, 0xB9, 0x05,
+ 0x32, 0x34, 0xE7, 0x82, 0xB9, 0x03, 0x68, 0x50,
+ 0x61, 0x02, 0x64, 0x61, 0x02, 0x41, 0x55, 0x03,
+ 0x62, 0x61, 0x72, 0x02, 0x6F, 0x56, 0x02, 0x70,
+ 0x63, 0x02, 0x64, 0x6D, 0x03, 0x64, 0x6D, 0x32,
+ 0x03, 0x64, 0x6D, 0x33, 0x02, 0x49, 0x55, 0x06,
+ // Bytes 2840 - 287f
+ 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90, 0x06, 0xE6,
+ 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x06, 0xE5, 0xA4,
+ 0xA7, 0xE6, 0xAD, 0xA3, 0x06, 0xE6, 0x98, 0x8E,
+ 0xE6, 0xB2, 0xBB, 0x0C, 0xE6, 0xA0, 0xAA, 0xE5,
+ 0xBC, 0x8F, 0xE4, 0xBC, 0x9A, 0xE7, 0xA4, 0xBE,
+ 0x02, 0x70, 0x41, 0x02, 0x6E, 0x41, 0x03, 0xCE,
+ 0xBC, 0x41, 0x02, 0x6D, 0x41, 0x02, 0x6B, 0x41,
+ 0x02, 0x4B, 0x42, 0x02, 0x4D, 0x42, 0x02, 0x47,
+ // Bytes 2880 - 28bf
+ 0x42, 0x03, 0x63, 0x61, 0x6C, 0x04, 0x6B, 0x63,
+ 0x61, 0x6C, 0x02, 0x70, 0x46, 0x02, 0x6E, 0x46,
+ 0x03, 0xCE, 0xBC, 0x46, 0x03, 0xCE, 0xBC, 0x67,
+ 0x02, 0x6D, 0x67, 0x02, 0x6B, 0x67, 0x02, 0x48,
+ 0x7A, 0x03, 0x6B, 0x48, 0x7A, 0x03, 0x4D, 0x48,
+ 0x7A, 0x03, 0x47, 0x48, 0x7A, 0x03, 0x54, 0x48,
+ 0x7A, 0x03, 0xCE, 0xBC, 0x6C, 0x02, 0x6D, 0x6C,
+ 0x02, 0x64, 0x6C, 0x02, 0x6B, 0x6C, 0x02, 0x66,
+ // Bytes 28c0 - 28ff
+ 0x6D, 0x02, 0x6E, 0x6D, 0x03, 0xCE, 0xBC, 0x6D,
+ 0x02, 0x6D, 0x6D, 0x02, 0x63, 0x6D, 0x02, 0x6B,
+ 0x6D, 0x03, 0x6D, 0x6D, 0x32, 0x03, 0x63, 0x6D,
+ 0x32, 0x02, 0x6D, 0x32, 0x03, 0x6B, 0x6D, 0x32,
+ 0x03, 0x6D, 0x6D, 0x33, 0x03, 0x63, 0x6D, 0x33,
+ 0x02, 0x6D, 0x33, 0x03, 0x6B, 0x6D, 0x33, 0x05,
+ 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x06, 0x6D, 0xE2,
+ 0x88, 0x95, 0x73, 0x32, 0x02, 0x50, 0x61, 0x03,
+ // Bytes 2900 - 293f
+ 0x6B, 0x50, 0x61, 0x03, 0x4D, 0x50, 0x61, 0x03,
+ 0x47, 0x50, 0x61, 0x03, 0x72, 0x61, 0x64, 0x07,
+ 0x72, 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x08,
+ 0x72, 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32,
+ 0x02, 0x70, 0x73, 0x02, 0x6E, 0x73, 0x03, 0xCE,
+ 0xBC, 0x73, 0x02, 0x6D, 0x73, 0x02, 0x70, 0x56,
+ 0x02, 0x6E, 0x56, 0x03, 0xCE, 0xBC, 0x56, 0x02,
+ 0x6D, 0x56, 0x02, 0x6B, 0x56, 0x02, 0x4D, 0x56,
+ // Bytes 2940 - 297f
+ 0x02, 0x70, 0x57, 0x02, 0x6E, 0x57, 0x03, 0xCE,
+ 0xBC, 0x57, 0x02, 0x6D, 0x57, 0x02, 0x6B, 0x57,
+ 0x02, 0x4D, 0x57, 0x03, 0x6B, 0xCE, 0xA9, 0x03,
+ 0x4D, 0xCE, 0xA9, 0x04, 0x61, 0x2E, 0x6D, 0x2E,
+ 0x02, 0x42, 0x71, 0x02, 0x63, 0x63, 0x02, 0x63,
+ 0x64, 0x06, 0x43, 0xE2, 0x88, 0x95, 0x6B, 0x67,
+ 0x03, 0x43, 0x6F, 0x2E, 0x02, 0x64, 0x42, 0x02,
+ 0x47, 0x79, 0x02, 0x68, 0x61, 0x02, 0x48, 0x50,
+ // Bytes 2980 - 29bf
+ 0x02, 0x69, 0x6E, 0x02, 0x4B, 0x4B, 0x02, 0x4B,
+ 0x4D, 0x02, 0x6B, 0x74, 0x02, 0x6C, 0x6D, 0x02,
+ 0x6C, 0x6E, 0x03, 0x6C, 0x6F, 0x67, 0x02, 0x6C,
+ 0x78, 0x02, 0x6D, 0x62, 0x03, 0x6D, 0x69, 0x6C,
+ 0x03, 0x6D, 0x6F, 0x6C, 0x02, 0x50, 0x48, 0x04,
+ 0x70, 0x2E, 0x6D, 0x2E, 0x03, 0x50, 0x50, 0x4D,
+ 0x02, 0x50, 0x52, 0x02, 0x73, 0x72, 0x02, 0x53,
+ 0x76, 0x02, 0x57, 0x62, 0x05, 0x56, 0xE2, 0x88,
+ // Bytes 29c0 - 29ff
+ 0x95, 0x6D, 0x05, 0x41, 0xE2, 0x88, 0x95, 0x6D,
+ 0x04, 0x31, 0xE6, 0x97, 0xA5, 0x04, 0x32, 0xE6,
+ 0x97, 0xA5, 0x04, 0x33, 0xE6, 0x97, 0xA5, 0x04,
+ 0x34, 0xE6, 0x97, 0xA5, 0x04, 0x35, 0xE6, 0x97,
+ 0xA5, 0x04, 0x36, 0xE6, 0x97, 0xA5, 0x04, 0x37,
+ 0xE6, 0x97, 0xA5, 0x04, 0x38, 0xE6, 0x97, 0xA5,
+ 0x04, 0x39, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x30,
+ 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x31, 0xE6, 0x97,
+ // Bytes 2a00 - 2a3f
+ 0xA5, 0x05, 0x31, 0x32, 0xE6, 0x97, 0xA5, 0x05,
+ 0x31, 0x33, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x34,
+ 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x35, 0xE6, 0x97,
+ 0xA5, 0x05, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x05,
+ 0x31, 0x37, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x38,
+ 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x39, 0xE6, 0x97,
+ 0xA5, 0x05, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x05,
+ 0x32, 0x31, 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x32,
+ // Bytes 2a40 - 2a7f
+ 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x33, 0xE6, 0x97,
+ 0xA5, 0x05, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x05,
+ 0x32, 0x35, 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x36,
+ 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x37, 0xE6, 0x97,
+ 0xA5, 0x05, 0x32, 0x38, 0xE6, 0x97, 0xA5, 0x05,
+ 0x32, 0x39, 0xE6, 0x97, 0xA5, 0x05, 0x33, 0x30,
+ 0xE6, 0x97, 0xA5, 0x05, 0x33, 0x31, 0xE6, 0x97,
+ 0xA5, 0x03, 0x67, 0x61, 0x6C, 0x03, 0xEA, 0x9D,
+ // Bytes 2a80 - 2abf
+ 0xAF, 0x03, 0xE8, 0xB1, 0x88, 0x03, 0xE6, 0x9B,
+ 0xB4, 0x03, 0xE8, 0xB3, 0x88, 0x03, 0xE6, 0xBB,
+ 0x91, 0x03, 0xE4, 0xB8, 0xB2, 0x03, 0xE5, 0x8F,
+ 0xA5, 0x03, 0xE5, 0xA5, 0x91, 0x03, 0xE5, 0x96,
+ 0x87, 0x03, 0xE5, 0xA5, 0x88, 0x03, 0xE6, 0x87,
+ 0xB6, 0x03, 0xE7, 0x99, 0xA9, 0x03, 0xE7, 0xBE,
+ 0x85, 0x03, 0xE8, 0x98, 0xBF, 0x03, 0xE8, 0x9E,
+ 0xBA, 0x03, 0xE8, 0xA3, 0xB8, 0x03, 0xE9, 0x82,
+ // Bytes 2ac0 - 2aff
+ 0x8F, 0x03, 0xE6, 0xA8, 0x82, 0x03, 0xE6, 0xB4,
+ 0x9B, 0x03, 0xE7, 0x83, 0x99, 0x03, 0xE7, 0x8F,
+ 0x9E, 0x03, 0xE8, 0x90, 0xBD, 0x03, 0xE9, 0x85,
+ 0xAA, 0x03, 0xE9, 0xA7, 0xB1, 0x03, 0xE4, 0xBA,
+ 0x82, 0x03, 0xE5, 0x8D, 0xB5, 0x03, 0xE6, 0xAC,
+ 0x84, 0x03, 0xE7, 0x88, 0x9B, 0x03, 0xE8, 0x98,
+ 0xAD, 0x03, 0xE9, 0xB8, 0x9E, 0x03, 0xE5, 0xB5,
+ 0x90, 0x03, 0xE6, 0xBF, 0xAB, 0x03, 0xE8, 0x97,
+ // Bytes 2b00 - 2b3f
+ 0x8D, 0x03, 0xE8, 0xA5, 0xA4, 0x03, 0xE6, 0x8B,
+ 0x89, 0x03, 0xE8, 0x87, 0x98, 0x03, 0xE8, 0xA0,
+ 0x9F, 0x03, 0xE5, 0xBB, 0x8A, 0x03, 0xE6, 0x9C,
+ 0x97, 0x03, 0xE6, 0xB5, 0xAA, 0x03, 0xE7, 0x8B,
+ 0xBC, 0x03, 0xE9, 0x83, 0x8E, 0x03, 0xE4, 0xBE,
+ 0x86, 0x03, 0xE5, 0x86, 0xB7, 0x03, 0xE5, 0x8B,
+ 0x9E, 0x03, 0xE6, 0x93, 0x84, 0x03, 0xE6, 0xAB,
+ 0x93, 0x03, 0xE7, 0x88, 0x90, 0x03, 0xE7, 0x9B,
+ // Bytes 2b40 - 2b7f
+ 0xA7, 0x03, 0xE8, 0x98, 0x86, 0x03, 0xE8, 0x99,
+ 0x9C, 0x03, 0xE8, 0xB7, 0xAF, 0x03, 0xE9, 0x9C,
+ 0xB2, 0x03, 0xE9, 0xAD, 0xAF, 0x03, 0xE9, 0xB7,
+ 0xBA, 0x03, 0xE7, 0xA2, 0x8C, 0x03, 0xE7, 0xA5,
+ 0xBF, 0x03, 0xE7, 0xB6, 0xA0, 0x03, 0xE8, 0x8F,
+ 0x89, 0x03, 0xE9, 0x8C, 0x84, 0x03, 0xE8, 0xAB,
+ 0x96, 0x03, 0xE5, 0xA3, 0x9F, 0x03, 0xE5, 0xBC,
+ 0x84, 0x03, 0xE7, 0xB1, 0xA0, 0x03, 0xE8, 0x81,
+ // Bytes 2b80 - 2bbf
+ 0xBE, 0x03, 0xE7, 0x89, 0xA2, 0x03, 0xE7, 0xA3,
+ 0x8A, 0x03, 0xE8, 0xB3, 0x82, 0x03, 0xE9, 0x9B,
+ 0xB7, 0x03, 0xE5, 0xA3, 0x98, 0x03, 0xE5, 0xB1,
+ 0xA2, 0x03, 0xE6, 0xA8, 0x93, 0x03, 0xE6, 0xB7,
+ 0x9A, 0x03, 0xE6, 0xBC, 0x8F, 0x03, 0xE7, 0xB4,
+ 0xAF, 0x03, 0xE7, 0xB8, 0xB7, 0x03, 0xE9, 0x99,
+ 0x8B, 0x03, 0xE5, 0x8B, 0x92, 0x03, 0xE8, 0x82,
+ 0x8B, 0x03, 0xE5, 0x87, 0x9C, 0x03, 0xE5, 0x87,
+ // Bytes 2bc0 - 2bff
+ 0x8C, 0x03, 0xE7, 0xA8, 0x9C, 0x03, 0xE7, 0xB6,
+ 0xBE, 0x03, 0xE8, 0x8F, 0xB1, 0x03, 0xE9, 0x99,
+ 0xB5, 0x03, 0xE8, 0xAE, 0x80, 0x03, 0xE6, 0x8B,
+ 0x8F, 0x03, 0xE8, 0xAB, 0xBE, 0x03, 0xE4, 0xB8,
+ 0xB9, 0x03, 0xE5, 0xAF, 0xA7, 0x03, 0xE6, 0x80,
+ 0x92, 0x03, 0xE7, 0x8E, 0x87, 0x03, 0xE7, 0x95,
+ 0xB0, 0x03, 0xE5, 0x8C, 0x97, 0x03, 0xE7, 0xA3,
+ 0xBB, 0x03, 0xE4, 0xBE, 0xBF, 0x03, 0xE5, 0xBE,
+ // Bytes 2c00 - 2c3f
+ 0xA9, 0x03, 0xE4, 0xB8, 0x8D, 0x03, 0xE6, 0xB3,
+ 0x8C, 0x03, 0xE6, 0x95, 0xB8, 0x03, 0xE7, 0xB4,
+ 0xA2, 0x03, 0xE5, 0x8F, 0x83, 0x03, 0xE5, 0xA1,
+ 0x9E, 0x03, 0xE7, 0x9C, 0x81, 0x03, 0xE8, 0x91,
+ 0x89, 0x03, 0xE8, 0xAA, 0xAA, 0x03, 0xE6, 0xAE,
+ 0xBA, 0x03, 0xE6, 0xB2, 0x88, 0x03, 0xE6, 0x8B,
+ 0xBE, 0x03, 0xE8, 0x8B, 0xA5, 0x03, 0xE6, 0x8E,
+ 0xA0, 0x03, 0xE7, 0x95, 0xA5, 0x03, 0xE4, 0xBA,
+ // Bytes 2c40 - 2c7f
+ 0xAE, 0x03, 0xE5, 0x85, 0xA9, 0x03, 0xE5, 0x87,
+ 0x89, 0x03, 0xE6, 0xA2, 0x81, 0x03, 0xE7, 0xB3,
+ 0xA7, 0x03, 0xE8, 0x89, 0xAF, 0x03, 0xE8, 0xAB,
+ 0x92, 0x03, 0xE9, 0x87, 0x8F, 0x03, 0xE5, 0x8B,
+ 0xB5, 0x03, 0xE5, 0x91, 0x82, 0x03, 0xE5, 0xBB,
+ 0xAC, 0x03, 0xE6, 0x97, 0x85, 0x03, 0xE6, 0xBF,
+ 0xBE, 0x03, 0xE7, 0xA4, 0xAA, 0x03, 0xE9, 0x96,
+ 0xAD, 0x03, 0xE9, 0xA9, 0xAA, 0x03, 0xE9, 0xBA,
+ // Bytes 2c80 - 2cbf
+ 0x97, 0x03, 0xE9, 0xBB, 0x8E, 0x03, 0xE6, 0x9B,
+ 0x86, 0x03, 0xE6, 0xAD, 0xB7, 0x03, 0xE8, 0xBD,
+ 0xA2, 0x03, 0xE5, 0xB9, 0xB4, 0x03, 0xE6, 0x86,
+ 0x90, 0x03, 0xE6, 0x88, 0x80, 0x03, 0xE6, 0x92,
+ 0x9A, 0x03, 0xE6, 0xBC, 0xA3, 0x03, 0xE7, 0x85,
+ 0x89, 0x03, 0xE7, 0x92, 0x89, 0x03, 0xE7, 0xA7,
+ 0x8A, 0x03, 0xE7, 0xB7, 0xB4, 0x03, 0xE8, 0x81,
+ 0xAF, 0x03, 0xE8, 0xBC, 0xA6, 0x03, 0xE8, 0x93,
+ // Bytes 2cc0 - 2cff
+ 0xAE, 0x03, 0xE9, 0x80, 0xA3, 0x03, 0xE9, 0x8D,
+ 0x8A, 0x03, 0xE5, 0x88, 0x97, 0x03, 0xE5, 0x8A,
+ 0xA3, 0x03, 0xE5, 0x92, 0xBD, 0x03, 0xE7, 0x83,
+ 0x88, 0x03, 0xE8, 0xA3, 0x82, 0x03, 0xE5, 0xBB,
+ 0x89, 0x03, 0xE5, 0xBF, 0xB5, 0x03, 0xE6, 0x8D,
+ 0xBB, 0x03, 0xE6, 0xAE, 0xAE, 0x03, 0xE7, 0xB0,
+ 0xBE, 0x03, 0xE7, 0x8D, 0xB5, 0x03, 0xE4, 0xBB,
+ 0xA4, 0x03, 0xE5, 0x9B, 0xB9, 0x03, 0xE5, 0xB6,
+ // Bytes 2d00 - 2d3f
+ 0xBA, 0x03, 0xE6, 0x80, 0x9C, 0x03, 0xE7, 0x8E,
+ 0xB2, 0x03, 0xE7, 0x91, 0xA9, 0x03, 0xE7, 0xBE,
+ 0x9A, 0x03, 0xE8, 0x81, 0x86, 0x03, 0xE9, 0x88,
+ 0xB4, 0x03, 0xE9, 0x9B, 0xB6, 0x03, 0xE9, 0x9D,
+ 0x88, 0x03, 0xE9, 0xA0, 0x98, 0x03, 0xE4, 0xBE,
+ 0x8B, 0x03, 0xE7, 0xA6, 0xAE, 0x03, 0xE9, 0x86,
+ 0xB4, 0x03, 0xE9, 0x9A, 0xB8, 0x03, 0xE6, 0x83,
+ 0xA1, 0x03, 0xE4, 0xBA, 0x86, 0x03, 0xE5, 0x83,
+ // Bytes 2d40 - 2d7f
+ 0x9A, 0x03, 0xE5, 0xAF, 0xAE, 0x03, 0xE5, 0xB0,
+ 0xBF, 0x03, 0xE6, 0x96, 0x99, 0x03, 0xE7, 0x87,
+ 0x8E, 0x03, 0xE7, 0x99, 0x82, 0x03, 0xE8, 0x93,
+ 0xBC, 0x03, 0xE9, 0x81, 0xBC, 0x03, 0xE6, 0x9A,
+ 0x88, 0x03, 0xE9, 0x98, 0xAE, 0x03, 0xE5, 0x8A,
+ 0x89, 0x03, 0xE6, 0x9D, 0xBB, 0x03, 0xE6, 0x9F,
+ 0xB3, 0x03, 0xE6, 0xB5, 0x81, 0x03, 0xE6, 0xBA,
+ 0x9C, 0x03, 0xE7, 0x90, 0x89, 0x03, 0xE7, 0x95,
+ // Bytes 2d80 - 2dbf
+ 0x99, 0x03, 0xE7, 0xA1, 0xAB, 0x03, 0xE7, 0xB4,
+ 0x90, 0x03, 0xE9, 0xA1, 0x9E, 0x03, 0xE6, 0x88,
+ 0xAE, 0x03, 0xE9, 0x99, 0xB8, 0x03, 0xE5, 0x80,
+ 0xAB, 0x03, 0xE5, 0xB4, 0x99, 0x03, 0xE6, 0xB7,
+ 0xAA, 0x03, 0xE8, 0xBC, 0xAA, 0x03, 0xE5, 0xBE,
+ 0x8B, 0x03, 0xE6, 0x85, 0x84, 0x03, 0xE6, 0xA0,
+ 0x97, 0x03, 0xE9, 0x9A, 0x86, 0x03, 0xE5, 0x88,
+ 0xA9, 0x03, 0xE5, 0x90, 0x8F, 0x03, 0xE5, 0xB1,
+ // Bytes 2dc0 - 2dff
+ 0xA5, 0x03, 0xE6, 0x98, 0x93, 0x03, 0xE6, 0x9D,
+ 0x8E, 0x03, 0xE6, 0xA2, 0xA8, 0x03, 0xE6, 0xB3,
+ 0xA5, 0x03, 0xE7, 0x90, 0x86, 0x03, 0xE7, 0x97,
+ 0xA2, 0x03, 0xE7, 0xBD, 0xB9, 0x03, 0xE8, 0xA3,
+ 0x8F, 0x03, 0xE8, 0xA3, 0xA1, 0x03, 0xE9, 0x9B,
+ 0xA2, 0x03, 0xE5, 0x8C, 0xBF, 0x03, 0xE6, 0xBA,
+ 0xBA, 0x03, 0xE5, 0x90, 0x9D, 0x03, 0xE7, 0x87,
+ 0x90, 0x03, 0xE7, 0x92, 0x98, 0x03, 0xE8, 0x97,
+ // Bytes 2e00 - 2e3f
+ 0xBA, 0x03, 0xE9, 0x9A, 0xA3, 0x03, 0xE9, 0xB1,
+ 0x97, 0x03, 0xE9, 0xBA, 0x9F, 0x03, 0xE6, 0x9E,
+ 0x97, 0x03, 0xE6, 0xB7, 0x8B, 0x03, 0xE8, 0x87,
+ 0xA8, 0x03, 0xE7, 0xAC, 0xA0, 0x03, 0xE7, 0xB2,
+ 0x92, 0x03, 0xE7, 0x8B, 0x80, 0x03, 0xE7, 0x82,
+ 0x99, 0x03, 0xE8, 0xAD, 0x98, 0x03, 0xE4, 0xBB,
+ 0x80, 0x03, 0xE8, 0x8C, 0xB6, 0x03, 0xE5, 0x88,
+ 0xBA, 0x03, 0xE5, 0x88, 0x87, 0x03, 0xE5, 0xBA,
+ // Bytes 2e40 - 2e7f
+ 0xA6, 0x03, 0xE6, 0x8B, 0x93, 0x03, 0xE7, 0xB3,
+ 0x96, 0x03, 0xE5, 0xAE, 0x85, 0x03, 0xE6, 0xB4,
+ 0x9E, 0x03, 0xE6, 0x9A, 0xB4, 0x03, 0xE8, 0xBC,
+ 0xBB, 0x03, 0xE9, 0x99, 0x8D, 0x03, 0xE5, 0xBB,
+ 0x93, 0x03, 0xE5, 0x85, 0x80, 0x03, 0xE5, 0x97,
+ 0x80, 0x03, 0xE5, 0xA1, 0x9A, 0x03, 0xE6, 0x99,
+ 0xB4, 0x03, 0xE5, 0x87, 0x9E, 0x03, 0xE7, 0x8C,
+ 0xAA, 0x03, 0xE7, 0x9B, 0x8A, 0x03, 0xE7, 0xA4,
+ // Bytes 2e80 - 2ebf
+ 0xBC, 0x03, 0xE7, 0xA5, 0x9E, 0x03, 0xE7, 0xA5,
+ 0xA5, 0x03, 0xE7, 0xA6, 0x8F, 0x03, 0xE9, 0x9D,
+ 0x96, 0x03, 0xE7, 0xB2, 0xBE, 0x03, 0xE8, 0x98,
+ 0x92, 0x03, 0xE8, 0xAB, 0xB8, 0x03, 0xE9, 0x80,
+ 0xB8, 0x03, 0xE9, 0x83, 0xBD, 0x03, 0xE9, 0xA3,
+ 0xAF, 0x03, 0xE9, 0xA3, 0xBC, 0x03, 0xE9, 0xA4,
+ 0xA8, 0x03, 0xE9, 0xB6, 0xB4, 0x03, 0xE4, 0xBE,
+ 0xAE, 0x03, 0xE5, 0x83, 0xA7, 0x03, 0xE5, 0x85,
+ // Bytes 2ec0 - 2eff
+ 0x8D, 0x03, 0xE5, 0x8B, 0x89, 0x03, 0xE5, 0x8B,
+ 0xA4, 0x03, 0xE5, 0x8D, 0x91, 0x03, 0xE5, 0x96,
+ 0x9D, 0x03, 0xE5, 0x98, 0x86, 0x03, 0xE5, 0x99,
+ 0xA8, 0x03, 0xE5, 0xA1, 0x80, 0x03, 0xE5, 0xA2,
+ 0xA8, 0x03, 0xE5, 0xB1, 0xA4, 0x03, 0xE6, 0x82,
+ 0x94, 0x03, 0xE6, 0x85, 0xA8, 0x03, 0xE6, 0x86,
+ 0x8E, 0x03, 0xE6, 0x87, 0xB2, 0x03, 0xE6, 0x95,
+ 0x8F, 0x03, 0xE6, 0x97, 0xA2, 0x03, 0xE6, 0x9A,
+ // Bytes 2f00 - 2f3f
+ 0x91, 0x03, 0xE6, 0xA2, 0x85, 0x03, 0xE6, 0xB5,
+ 0xB7, 0x03, 0xE6, 0xB8, 0x9A, 0x03, 0xE6, 0xBC,
+ 0xA2, 0x03, 0xE7, 0x85, 0xAE, 0x03, 0xE7, 0x88,
+ 0xAB, 0x03, 0xE7, 0x90, 0xA2, 0x03, 0xE7, 0xA2,
+ 0x91, 0x03, 0xE7, 0xA5, 0x89, 0x03, 0xE7, 0xA5,
+ 0x88, 0x03, 0xE7, 0xA5, 0x90, 0x03, 0xE7, 0xA5,
+ 0x96, 0x03, 0xE7, 0xA6, 0x8D, 0x03, 0xE7, 0xA6,
+ 0x8E, 0x03, 0xE7, 0xA9, 0x80, 0x03, 0xE7, 0xAA,
+ // Bytes 2f40 - 2f7f
+ 0x81, 0x03, 0xE7, 0xAF, 0x80, 0x03, 0xE7, 0xB8,
+ 0x89, 0x03, 0xE7, 0xB9, 0x81, 0x03, 0xE7, 0xBD,
+ 0xB2, 0x03, 0xE8, 0x80, 0x85, 0x03, 0xE8, 0x87,
+ 0xAD, 0x03, 0xE8, 0x89, 0xB9, 0x03, 0xE8, 0x91,
+ 0x97, 0x03, 0xE8, 0xA4, 0x90, 0x03, 0xE8, 0xA6,
+ 0x96, 0x03, 0xE8, 0xAC, 0x81, 0x03, 0xE8, 0xAC,
+ 0xB9, 0x03, 0xE8, 0xB3, 0x93, 0x03, 0xE8, 0xB4,
+ 0x88, 0x03, 0xE8, 0xBE, 0xB6, 0x03, 0xE9, 0x9B,
+ // Bytes 2f80 - 2fbf
+ 0xA3, 0x03, 0xE9, 0x9F, 0xBF, 0x03, 0xE9, 0xA0,
+ 0xBB, 0x03, 0xE6, 0x81, 0xB5, 0x04, 0xF0, 0xA4,
+ 0x8B, 0xAE, 0x03, 0xE8, 0x88, 0x98, 0x03, 0xE4,
+ 0xB8, 0xA6, 0x03, 0xE5, 0x86, 0xB5, 0x03, 0xE5,
+ 0x85, 0xA8, 0x03, 0xE4, 0xBE, 0x80, 0x03, 0xE5,
+ 0x85, 0x85, 0x03, 0xE5, 0x86, 0x80, 0x03, 0xE5,
+ 0x8B, 0x87, 0x03, 0xE5, 0x8B, 0xBA, 0x03, 0xE5,
+ 0x95, 0x95, 0x03, 0xE5, 0x96, 0x99, 0x03, 0xE5,
+ // Bytes 2fc0 - 2fff
+ 0x97, 0xA2, 0x03, 0xE5, 0xA2, 0xB3, 0x03, 0xE5,
+ 0xA5, 0x84, 0x03, 0xE5, 0xA5, 0x94, 0x03, 0xE5,
+ 0xA9, 0xA2, 0x03, 0xE5, 0xAC, 0xA8, 0x03, 0xE5,
+ 0xBB, 0x92, 0x03, 0xE5, 0xBB, 0x99, 0x03, 0xE5,
+ 0xBD, 0xA9, 0x03, 0xE5, 0xBE, 0xAD, 0x03, 0xE6,
+ 0x83, 0x98, 0x03, 0xE6, 0x85, 0x8E, 0x03, 0xE6,
+ 0x84, 0x88, 0x03, 0xE6, 0x85, 0xA0, 0x03, 0xE6,
+ 0x88, 0xB4, 0x03, 0xE6, 0x8F, 0x84, 0x03, 0xE6,
+ // Bytes 3000 - 303f
+ 0x90, 0x9C, 0x03, 0xE6, 0x91, 0x92, 0x03, 0xE6,
+ 0x95, 0x96, 0x03, 0xE6, 0x9C, 0x9B, 0x03, 0xE6,
+ 0x9D, 0x96, 0x03, 0xE6, 0xBB, 0x9B, 0x03, 0xE6,
+ 0xBB, 0x8B, 0x03, 0xE7, 0x80, 0x9E, 0x03, 0xE7,
+ 0x9E, 0xA7, 0x03, 0xE7, 0x88, 0xB5, 0x03, 0xE7,
+ 0x8A, 0xAF, 0x03, 0xE7, 0x91, 0xB1, 0x03, 0xE7,
+ 0x94, 0x86, 0x03, 0xE7, 0x94, 0xBB, 0x03, 0xE7,
+ 0x98, 0x9D, 0x03, 0xE7, 0x98, 0x9F, 0x03, 0xE7,
+ // Bytes 3040 - 307f
+ 0x9B, 0x9B, 0x03, 0xE7, 0x9B, 0xB4, 0x03, 0xE7,
+ 0x9D, 0x8A, 0x03, 0xE7, 0x9D, 0x80, 0x03, 0xE7,
+ 0xA3, 0x8C, 0x03, 0xE7, 0xAA, 0xB1, 0x03, 0xE7,
+ 0xB1, 0xBB, 0x03, 0xE7, 0xB5, 0x9B, 0x03, 0xE7,
+ 0xBC, 0xBE, 0x03, 0xE8, 0x8D, 0x92, 0x03, 0xE8,
+ 0x8F, 0xAF, 0x03, 0xE8, 0x9D, 0xB9, 0x03, 0xE8,
+ 0xA5, 0x81, 0x03, 0xE8, 0xA6, 0x86, 0x03, 0xE8,
+ 0xAA, 0xBF, 0x03, 0xE8, 0xAB, 0x8B, 0x03, 0xE8,
+ // Bytes 3080 - 30bf
+ 0xAB, 0xAD, 0x03, 0xE8, 0xAE, 0x8A, 0x03, 0xE8,
+ 0xBC, 0xB8, 0x03, 0xE9, 0x81, 0xB2, 0x03, 0xE9,
+ 0x86, 0x99, 0x03, 0xE9, 0x89, 0xB6, 0x03, 0xE9,
+ 0x99, 0xBC, 0x03, 0xE9, 0x9F, 0x9B, 0x03, 0xE9,
+ 0xA0, 0x8B, 0x03, 0xE9, 0xAC, 0x92, 0x04, 0xF0,
+ 0xA2, 0xA1, 0x8A, 0x04, 0xF0, 0xA2, 0xA1, 0x84,
+ 0x04, 0xF0, 0xA3, 0x8F, 0x95, 0x03, 0xE3, 0xAE,
+ 0x9D, 0x03, 0xE4, 0x80, 0x98, 0x03, 0xE4, 0x80,
+ // Bytes 30c0 - 30ff
+ 0xB9, 0x04, 0xF0, 0xA5, 0x89, 0x89, 0x04, 0xF0,
+ 0xA5, 0xB3, 0x90, 0x04, 0xF0, 0xA7, 0xBB, 0x93,
+ 0x03, 0xE9, 0xBD, 0x83, 0x03, 0xE9, 0xBE, 0x8E,
+ 0x02, 0x66, 0x66, 0x02, 0x66, 0x69, 0x02, 0x66,
+ 0x6C, 0x03, 0x66, 0x66, 0x69, 0x03, 0x66, 0x66,
+ 0x6C, 0x02, 0x73, 0x74, 0x04, 0xD5, 0xB4, 0xD5,
+ 0xB6, 0x04, 0xD5, 0xB4, 0xD5, 0xA5, 0x04, 0xD5,
+ 0xB4, 0xD5, 0xAB, 0x04, 0xD5, 0xBE, 0xD5, 0xB6,
+ // Bytes 3100 - 313f
+ 0x04, 0xD5, 0xB4, 0xD5, 0xAD, 0x04, 0xD7, 0x99,
+ 0xD6, 0xB4, 0x04, 0xD7, 0xB2, 0xD6, 0xB7, 0x02,
+ 0xD7, 0xA2, 0x02, 0xD7, 0x94, 0x02, 0xD7, 0x9B,
+ 0x02, 0xD7, 0x9C, 0x02, 0xD7, 0x9D, 0x02, 0xD7,
+ 0xA8, 0x02, 0xD7, 0xAA, 0x04, 0xD7, 0xA9, 0xD7,
+ 0x81, 0x04, 0xD7, 0xA9, 0xD7, 0x82, 0x06, 0xD7,
+ 0xA9, 0xD6, 0xBC, 0xD7, 0x81, 0x06, 0xD7, 0xA9,
+ 0xD6, 0xBC, 0xD7, 0x82, 0x04, 0xD7, 0x90, 0xD6,
+ // Bytes 3140 - 317f
+ 0xB7, 0x04, 0xD7, 0x90, 0xD6, 0xB8, 0x04, 0xD7,
+ 0x90, 0xD6, 0xBC, 0x04, 0xD7, 0x91, 0xD6, 0xBC,
+ 0x04, 0xD7, 0x92, 0xD6, 0xBC, 0x04, 0xD7, 0x93,
+ 0xD6, 0xBC, 0x04, 0xD7, 0x94, 0xD6, 0xBC, 0x04,
+ 0xD7, 0x95, 0xD6, 0xBC, 0x04, 0xD7, 0x96, 0xD6,
+ 0xBC, 0x04, 0xD7, 0x98, 0xD6, 0xBC, 0x04, 0xD7,
+ 0x99, 0xD6, 0xBC, 0x04, 0xD7, 0x9A, 0xD6, 0xBC,
+ 0x04, 0xD7, 0x9B, 0xD6, 0xBC, 0x04, 0xD7, 0x9C,
+ // Bytes 3180 - 31bf
+ 0xD6, 0xBC, 0x04, 0xD7, 0x9E, 0xD6, 0xBC, 0x04,
+ 0xD7, 0xA0, 0xD6, 0xBC, 0x04, 0xD7, 0xA1, 0xD6,
+ 0xBC, 0x04, 0xD7, 0xA3, 0xD6, 0xBC, 0x04, 0xD7,
+ 0xA4, 0xD6, 0xBC, 0x04, 0xD7, 0xA6, 0xD6, 0xBC,
+ 0x04, 0xD7, 0xA7, 0xD6, 0xBC, 0x04, 0xD7, 0xA8,
+ 0xD6, 0xBC, 0x04, 0xD7, 0xA9, 0xD6, 0xBC, 0x04,
+ 0xD7, 0xAA, 0xD6, 0xBC, 0x04, 0xD7, 0x95, 0xD6,
+ 0xB9, 0x04, 0xD7, 0x91, 0xD6, 0xBF, 0x04, 0xD7,
+ // Bytes 31c0 - 31ff
+ 0x9B, 0xD6, 0xBF, 0x04, 0xD7, 0xA4, 0xD6, 0xBF,
+ 0x04, 0xD7, 0x90, 0xD7, 0x9C, 0x02, 0xD9, 0xB1,
+ 0x02, 0xD9, 0xBB, 0x02, 0xD9, 0xBE, 0x02, 0xDA,
+ 0x80, 0x02, 0xD9, 0xBA, 0x02, 0xD9, 0xBF, 0x02,
+ 0xD9, 0xB9, 0x02, 0xDA, 0xA4, 0x02, 0xDA, 0xA6,
+ 0x02, 0xDA, 0x84, 0x02, 0xDA, 0x83, 0x02, 0xDA,
+ 0x86, 0x02, 0xDA, 0x87, 0x02, 0xDA, 0x8D, 0x02,
+ 0xDA, 0x8C, 0x02, 0xDA, 0x8E, 0x02, 0xDA, 0x88,
+ // Bytes 3200 - 323f
+ 0x02, 0xDA, 0x98, 0x02, 0xDA, 0x91, 0x02, 0xDA,
+ 0xA9, 0x02, 0xDA, 0xAF, 0x02, 0xDA, 0xB3, 0x02,
+ 0xDA, 0xB1, 0x02, 0xDA, 0xBA, 0x02, 0xDA, 0xBB,
+ 0x02, 0xDB, 0x81, 0x02, 0xDA, 0xBE, 0x02, 0xDB,
+ 0x92, 0x02, 0xDA, 0xAD, 0x02, 0xDB, 0x87, 0x02,
+ 0xDB, 0x86, 0x02, 0xDB, 0x88, 0x02, 0xDB, 0x8B,
+ 0x02, 0xDB, 0x85, 0x02, 0xDB, 0x89, 0x02, 0xDB,
+ 0x90, 0x02, 0xD9, 0x89, 0x06, 0xD9, 0x8A, 0xD9,
+ // Bytes 3240 - 327f
+ 0x94, 0xD8, 0xA7, 0x06, 0xD9, 0x8A, 0xD9, 0x94,
+ 0xDB, 0x95, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+ 0x88, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x87,
+ 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x06,
+ 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x88, 0x06, 0xD9,
+ 0x8A, 0xD9, 0x94, 0xDB, 0x90, 0x06, 0xD9, 0x8A,
+ 0xD9, 0x94, 0xD9, 0x89, 0x02, 0xDB, 0x8C, 0x06,
+ 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC, 0x06, 0xD9,
+ // Bytes 3280 - 32bf
+ 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x06, 0xD9, 0x8A,
+ 0xD9, 0x94, 0xD9, 0x85, 0x06, 0xD9, 0x8A, 0xD9,
+ 0x94, 0xD9, 0x8A, 0x04, 0xD8, 0xA8, 0xD8, 0xAC,
+ 0x04, 0xD8, 0xA8, 0xD8, 0xAD, 0x04, 0xD8, 0xA8,
+ 0xD8, 0xAE, 0x04, 0xD8, 0xA8, 0xD9, 0x85, 0x04,
+ 0xD8, 0xA8, 0xD9, 0x89, 0x04, 0xD8, 0xA8, 0xD9,
+ 0x8A, 0x04, 0xD8, 0xAA, 0xD8, 0xAC, 0x04, 0xD8,
+ 0xAA, 0xD8, 0xAD, 0x04, 0xD8, 0xAA, 0xD8, 0xAE,
+ // Bytes 32c0 - 32ff
+ 0x04, 0xD8, 0xAA, 0xD9, 0x85, 0x04, 0xD8, 0xAA,
+ 0xD9, 0x89, 0x04, 0xD8, 0xAA, 0xD9, 0x8A, 0x04,
+ 0xD8, 0xAB, 0xD8, 0xAC, 0x04, 0xD8, 0xAB, 0xD9,
+ 0x85, 0x04, 0xD8, 0xAB, 0xD9, 0x89, 0x04, 0xD8,
+ 0xAB, 0xD9, 0x8A, 0x04, 0xD8, 0xAC, 0xD8, 0xAD,
+ 0x04, 0xD8, 0xAC, 0xD9, 0x85, 0x04, 0xD8, 0xAD,
+ 0xD8, 0xAC, 0x04, 0xD8, 0xAD, 0xD9, 0x85, 0x04,
+ 0xD8, 0xAE, 0xD8, 0xAC, 0x04, 0xD8, 0xAE, 0xD8,
+ // Bytes 3300 - 333f
+ 0xAD, 0x04, 0xD8, 0xAE, 0xD9, 0x85, 0x04, 0xD8,
+ 0xB3, 0xD8, 0xAC, 0x04, 0xD8, 0xB3, 0xD8, 0xAD,
+ 0x04, 0xD8, 0xB3, 0xD8, 0xAE, 0x04, 0xD8, 0xB3,
+ 0xD9, 0x85, 0x04, 0xD8, 0xB5, 0xD8, 0xAD, 0x04,
+ 0xD8, 0xB5, 0xD9, 0x85, 0x04, 0xD8, 0xB6, 0xD8,
+ 0xAC, 0x04, 0xD8, 0xB6, 0xD8, 0xAD, 0x04, 0xD8,
+ 0xB6, 0xD8, 0xAE, 0x04, 0xD8, 0xB6, 0xD9, 0x85,
+ 0x04, 0xD8, 0xB7, 0xD8, 0xAD, 0x04, 0xD8, 0xB7,
+ // Bytes 3340 - 337f
+ 0xD9, 0x85, 0x04, 0xD8, 0xB8, 0xD9, 0x85, 0x04,
+ 0xD8, 0xB9, 0xD8, 0xAC, 0x04, 0xD8, 0xB9, 0xD9,
+ 0x85, 0x04, 0xD8, 0xBA, 0xD8, 0xAC, 0x04, 0xD8,
+ 0xBA, 0xD9, 0x85, 0x04, 0xD9, 0x81, 0xD8, 0xAC,
+ 0x04, 0xD9, 0x81, 0xD8, 0xAD, 0x04, 0xD9, 0x81,
+ 0xD8, 0xAE, 0x04, 0xD9, 0x81, 0xD9, 0x85, 0x04,
+ 0xD9, 0x81, 0xD9, 0x89, 0x04, 0xD9, 0x81, 0xD9,
+ 0x8A, 0x04, 0xD9, 0x82, 0xD8, 0xAD, 0x04, 0xD9,
+ // Bytes 3380 - 33bf
+ 0x82, 0xD9, 0x85, 0x04, 0xD9, 0x82, 0xD9, 0x89,
+ 0x04, 0xD9, 0x82, 0xD9, 0x8A, 0x04, 0xD9, 0x83,
+ 0xD8, 0xA7, 0x04, 0xD9, 0x83, 0xD8, 0xAC, 0x04,
+ 0xD9, 0x83, 0xD8, 0xAD, 0x04, 0xD9, 0x83, 0xD8,
+ 0xAE, 0x04, 0xD9, 0x83, 0xD9, 0x84, 0x04, 0xD9,
+ 0x83, 0xD9, 0x85, 0x04, 0xD9, 0x83, 0xD9, 0x89,
+ 0x04, 0xD9, 0x83, 0xD9, 0x8A, 0x04, 0xD9, 0x84,
+ 0xD8, 0xAC, 0x04, 0xD9, 0x84, 0xD8, 0xAD, 0x04,
+ // Bytes 33c0 - 33ff
+ 0xD9, 0x84, 0xD8, 0xAE, 0x04, 0xD9, 0x84, 0xD9,
+ 0x85, 0x04, 0xD9, 0x84, 0xD9, 0x89, 0x04, 0xD9,
+ 0x84, 0xD9, 0x8A, 0x04, 0xD9, 0x85, 0xD8, 0xAC,
+ 0x04, 0xD9, 0x85, 0xD8, 0xAD, 0x04, 0xD9, 0x85,
+ 0xD8, 0xAE, 0x04, 0xD9, 0x85, 0xD9, 0x85, 0x04,
+ 0xD9, 0x85, 0xD9, 0x89, 0x04, 0xD9, 0x85, 0xD9,
+ 0x8A, 0x04, 0xD9, 0x86, 0xD8, 0xAC, 0x04, 0xD9,
+ 0x86, 0xD8, 0xAD, 0x04, 0xD9, 0x86, 0xD8, 0xAE,
+ // Bytes 3400 - 343f
+ 0x04, 0xD9, 0x86, 0xD9, 0x85, 0x04, 0xD9, 0x86,
+ 0xD9, 0x89, 0x04, 0xD9, 0x86, 0xD9, 0x8A, 0x04,
+ 0xD9, 0x87, 0xD8, 0xAC, 0x04, 0xD9, 0x87, 0xD9,
+ 0x85, 0x04, 0xD9, 0x87, 0xD9, 0x89, 0x04, 0xD9,
+ 0x87, 0xD9, 0x8A, 0x04, 0xD9, 0x8A, 0xD8, 0xAC,
+ 0x04, 0xD9, 0x8A, 0xD8, 0xAD, 0x04, 0xD9, 0x8A,
+ 0xD8, 0xAE, 0x04, 0xD9, 0x8A, 0xD9, 0x85, 0x04,
+ 0xD9, 0x8A, 0xD9, 0x89, 0x04, 0xD9, 0x8A, 0xD9,
+ // Bytes 3440 - 347f
+ 0x8A, 0x04, 0xD8, 0xB0, 0xD9, 0xB0, 0x04, 0xD8,
+ 0xB1, 0xD9, 0xB0, 0x04, 0xD9, 0x89, 0xD9, 0xB0,
+ 0x05, 0x20, 0xD9, 0x8C, 0xD9, 0x91, 0x05, 0x20,
+ 0xD9, 0x8D, 0xD9, 0x91, 0x05, 0x20, 0xD9, 0x8E,
+ 0xD9, 0x91, 0x05, 0x20, 0xD9, 0x8F, 0xD9, 0x91,
+ 0x05, 0x20, 0xD9, 0x90, 0xD9, 0x91, 0x05, 0x20,
+ 0xD9, 0x91, 0xD9, 0xB0, 0x06, 0xD9, 0x8A, 0xD9,
+ 0x94, 0xD8, 0xB1, 0x06, 0xD9, 0x8A, 0xD9, 0x94,
+ // Bytes 3480 - 34bf
+ 0xD8, 0xB2, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+ 0x86, 0x04, 0xD8, 0xA8, 0xD8, 0xB1, 0x04, 0xD8,
+ 0xA8, 0xD8, 0xB2, 0x04, 0xD8, 0xA8, 0xD9, 0x86,
+ 0x04, 0xD8, 0xAA, 0xD8, 0xB1, 0x04, 0xD8, 0xAA,
+ 0xD8, 0xB2, 0x04, 0xD8, 0xAA, 0xD9, 0x86, 0x04,
+ 0xD8, 0xAB, 0xD8, 0xB1, 0x04, 0xD8, 0xAB, 0xD8,
+ 0xB2, 0x04, 0xD8, 0xAB, 0xD9, 0x86, 0x04, 0xD9,
+ 0x85, 0xD8, 0xA7, 0x04, 0xD9, 0x86, 0xD8, 0xB1,
+ // Bytes 34c0 - 34ff
+ 0x04, 0xD9, 0x86, 0xD8, 0xB2, 0x04, 0xD9, 0x86,
+ 0xD9, 0x86, 0x04, 0xD9, 0x8A, 0xD8, 0xB1, 0x04,
+ 0xD9, 0x8A, 0xD8, 0xB2, 0x04, 0xD9, 0x8A, 0xD9,
+ 0x86, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE,
+ 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x87, 0x04,
+ 0xD8, 0xA8, 0xD9, 0x87, 0x04, 0xD8, 0xAA, 0xD9,
+ 0x87, 0x04, 0xD8, 0xB5, 0xD8, 0xAE, 0x04, 0xD9,
+ 0x84, 0xD9, 0x87, 0x04, 0xD9, 0x86, 0xD9, 0x87,
+ // Bytes 3500 - 353f
+ 0x04, 0xD9, 0x87, 0xD9, 0xB0, 0x04, 0xD9, 0x8A,
+ 0xD9, 0x87, 0x04, 0xD8, 0xAB, 0xD9, 0x87, 0x04,
+ 0xD8, 0xB3, 0xD9, 0x87, 0x04, 0xD8, 0xB4, 0xD9,
+ 0x85, 0x04, 0xD8, 0xB4, 0xD9, 0x87, 0x06, 0xD9,
+ 0x80, 0xD9, 0x8E, 0xD9, 0x91, 0x06, 0xD9, 0x80,
+ 0xD9, 0x8F, 0xD9, 0x91, 0x06, 0xD9, 0x80, 0xD9,
+ 0x90, 0xD9, 0x91, 0x04, 0xD8, 0xB7, 0xD9, 0x89,
+ 0x04, 0xD8, 0xB7, 0xD9, 0x8A, 0x04, 0xD8, 0xB9,
+ // Bytes 3540 - 357f
+ 0xD9, 0x89, 0x04, 0xD8, 0xB9, 0xD9, 0x8A, 0x04,
+ 0xD8, 0xBA, 0xD9, 0x89, 0x04, 0xD8, 0xBA, 0xD9,
+ 0x8A, 0x04, 0xD8, 0xB3, 0xD9, 0x89, 0x04, 0xD8,
+ 0xB3, 0xD9, 0x8A, 0x04, 0xD8, 0xB4, 0xD9, 0x89,
+ 0x04, 0xD8, 0xB4, 0xD9, 0x8A, 0x04, 0xD8, 0xAD,
+ 0xD9, 0x89, 0x04, 0xD8, 0xAD, 0xD9, 0x8A, 0x04,
+ 0xD8, 0xAC, 0xD9, 0x89, 0x04, 0xD8, 0xAC, 0xD9,
+ 0x8A, 0x04, 0xD8, 0xAE, 0xD9, 0x89, 0x04, 0xD8,
+ // Bytes 3580 - 35bf
+ 0xAE, 0xD9, 0x8A, 0x04, 0xD8, 0xB5, 0xD9, 0x89,
+ 0x04, 0xD8, 0xB5, 0xD9, 0x8A, 0x04, 0xD8, 0xB6,
+ 0xD9, 0x89, 0x04, 0xD8, 0xB6, 0xD9, 0x8A, 0x04,
+ 0xD8, 0xB4, 0xD8, 0xAC, 0x04, 0xD8, 0xB4, 0xD8,
+ 0xAD, 0x04, 0xD8, 0xB4, 0xD8, 0xAE, 0x04, 0xD8,
+ 0xB4, 0xD8, 0xB1, 0x04, 0xD8, 0xB3, 0xD8, 0xB1,
+ 0x04, 0xD8, 0xB5, 0xD8, 0xB1, 0x04, 0xD8, 0xB6,
+ 0xD8, 0xB1, 0x04, 0xD8, 0xA7, 0xD9, 0x8B, 0x06,
+ // Bytes 35c0 - 35ff
+ 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85, 0x06, 0xD8,
+ 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD8, 0xAA,
+ 0xD8, 0xAD, 0xD9, 0x85, 0x06, 0xD8, 0xAA, 0xD8,
+ 0xAE, 0xD9, 0x85, 0x06, 0xD8, 0xAA, 0xD9, 0x85,
+ 0xD8, 0xAC, 0x06, 0xD8, 0xAA, 0xD9, 0x85, 0xD8,
+ 0xAD, 0x06, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE,
+ 0x06, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, 0xAD, 0x06,
+ 0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8,
+ // Bytes 3600 - 363f
+ 0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD8, 0xB3,
+ 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD8, 0xB3, 0xD8,
+ 0xAC, 0xD8, 0xAD, 0x06, 0xD8, 0xB3, 0xD8, 0xAC,
+ 0xD9, 0x89, 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD8,
+ 0xAD, 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC,
+ 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD9, 0x85, 0x06,
+ 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x06, 0xD8,
+ 0xB5, 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xB4,
+ // Bytes 3640 - 367f
+ 0xD8, 0xAD, 0xD9, 0x85, 0x06, 0xD8, 0xB4, 0xD8,
+ 0xAC, 0xD9, 0x8A, 0x06, 0xD8, 0xB4, 0xD9, 0x85,
+ 0xD8, 0xAE, 0x06, 0xD8, 0xB4, 0xD9, 0x85, 0xD9,
+ 0x85, 0x06, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x89,
+ 0x06, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x06,
+ 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD8,
+ 0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xB7,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xB9, 0xD8,
+ // Bytes 3680 - 36bf
+ 0xAC, 0xD9, 0x85, 0x06, 0xD8, 0xB9, 0xD9, 0x85,
+ 0xD9, 0x85, 0x06, 0xD8, 0xB9, 0xD9, 0x85, 0xD9,
+ 0x89, 0x06, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85,
+ 0x06, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x06,
+ 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD9,
+ 0x81, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9, 0x82,
+ 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD9, 0x82, 0xD9,
+ 0x85, 0xD9, 0x85, 0x06, 0xD9, 0x84, 0xD8, 0xAD,
+ // Bytes 36c0 - 36ff
+ 0xD9, 0x85, 0x06, 0xD9, 0x84, 0xD8, 0xAD, 0xD9,
+ 0x8A, 0x06, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89,
+ 0x06, 0xD9, 0x84, 0xD8, 0xAC, 0xD8, 0xAC, 0x06,
+ 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9,
+ 0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD9, 0x85,
+ 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD9, 0x85, 0xD8,
+ 0xAD, 0xD9, 0x85, 0x06, 0xD9, 0x85, 0xD8, 0xAD,
+ 0xD9, 0x8A, 0x06, 0xD9, 0x85, 0xD8, 0xAC, 0xD8,
+ // Bytes 3700 - 373f
+ 0xAD, 0x06, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x85,
+ 0x06, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0x06,
+ 0xD9, 0x85, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9,
+ 0x85, 0xD8, 0xAC, 0xD8, 0xAE, 0x06, 0xD9, 0x87,
+ 0xD9, 0x85, 0xD8, 0xAC, 0x06, 0xD9, 0x87, 0xD9,
+ 0x85, 0xD9, 0x85, 0x06, 0xD9, 0x86, 0xD8, 0xAD,
+ 0xD9, 0x85, 0x06, 0xD9, 0x86, 0xD8, 0xAD, 0xD9,
+ 0x89, 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85,
+ // Bytes 3740 - 377f
+ 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x06,
+ 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9,
+ 0x86, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD9, 0x8A,
+ 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xA8, 0xD8,
+ 0xAE, 0xD9, 0x8A, 0x06, 0xD8, 0xAA, 0xD8, 0xAC,
+ 0xD9, 0x8A, 0x06, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9,
+ 0x89, 0x06, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, 0x8A,
+ 0x06, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, 0x89, 0x06,
+ // Bytes 3780 - 37bf
+ 0xD8, 0xAA, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8,
+ 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD8, 0xAC,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xAC, 0xD8,
+ 0xAD, 0xD9, 0x89, 0x06, 0xD8, 0xAC, 0xD9, 0x85,
+ 0xD9, 0x89, 0x06, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9,
+ 0x89, 0x06, 0xD8, 0xB5, 0xD8, 0xAD, 0xD9, 0x8A,
+ 0x06, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9, 0x8A, 0x06,
+ 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A, 0x06, 0xD9,
+ // Bytes 37c0 - 37ff
+ 0x84, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9, 0x84,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD8,
+ 0xAD, 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD8, 0xAC,
+ 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD9, 0x85, 0xD9,
+ 0x8A, 0x06, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x8A,
+ 0x06, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x06,
+ 0xD9, 0x86, 0xD8, 0xAD, 0xD9, 0x8A, 0x06, 0xD8,
+ 0xB9, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x83,
+ // Bytes 3800 - 383f
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x86, 0xD8,
+ 0xAC, 0xD8, 0xAD, 0x06, 0xD9, 0x85, 0xD8, 0xAE,
+ 0xD9, 0x8A, 0x06, 0xD9, 0x84, 0xD8, 0xAC, 0xD9,
+ 0x85, 0x06, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85,
+ 0x06, 0xD8, 0xAC, 0xD8, 0xAD, 0xD9, 0x8A, 0x06,
+ 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9,
+ 0x85, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9, 0x81,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xA8, 0xD8,
+ // Bytes 3840 - 387f
+ 0xAD, 0xD9, 0x8A, 0x06, 0xD8, 0xB3, 0xD8, 0xAE,
+ 0xD9, 0x8A, 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9,
+ 0x8A, 0x06, 0xD8, 0xB5, 0xD9, 0x84, 0xDB, 0x92,
+ 0x06, 0xD9, 0x82, 0xD9, 0x84, 0xDB, 0x92, 0x08,
+ 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87,
+ 0x08, 0xD8, 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8,
+ 0xB1, 0x08, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85,
+ 0xD8, 0xAF, 0x08, 0xD8, 0xB5, 0xD9, 0x84, 0xD8,
+ // Bytes 3880 - 38bf
+ 0xB9, 0xD9, 0x85, 0x08, 0xD8, 0xB1, 0xD8, 0xB3,
+ 0xD9, 0x88, 0xD9, 0x84, 0x08, 0xD8, 0xB9, 0xD9,
+ 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x08, 0xD9, 0x88,
+ 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xD8,
+ 0xB5, 0xD9, 0x84, 0xD9, 0x89, 0x21, 0xD8, 0xB5,
+ 0xD9, 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9,
+ 0x84, 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9,
+ 0xD9, 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9,
+ // Bytes 38c0 - 38ff
+ 0x88, 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x0F,
+ 0xD8, 0xAC, 0xD9, 0x84, 0x20, 0xD8, 0xAC, 0xD9,
+ 0x84, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x87, 0x08,
+ 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7, 0xD9, 0x84,
+ 0x01, 0x2C, 0x03, 0xE3, 0x80, 0x81, 0x03, 0xE3,
+ 0x80, 0x82, 0x01, 0x3A, 0x01, 0x21, 0x01, 0x3F,
+ 0x03, 0xE3, 0x80, 0x96, 0x03, 0xE3, 0x80, 0x97,
+ 0x03, 0xE2, 0x80, 0x94, 0x03, 0xE2, 0x80, 0x93,
+ // Bytes 3900 - 393f
+ 0x01, 0x5F, 0x01, 0x7B, 0x01, 0x7D, 0x03, 0xE3,
+ 0x80, 0x94, 0x03, 0xE3, 0x80, 0x95, 0x03, 0xE3,
+ 0x80, 0x90, 0x03, 0xE3, 0x80, 0x91, 0x03, 0xE3,
+ 0x80, 0x8A, 0x03, 0xE3, 0x80, 0x8B, 0x03, 0xE3,
+ 0x80, 0x8C, 0x03, 0xE3, 0x80, 0x8D, 0x03, 0xE3,
+ 0x80, 0x8E, 0x03, 0xE3, 0x80, 0x8F, 0x01, 0x5B,
+ 0x01, 0x5D, 0x01, 0x23, 0x01, 0x26, 0x01, 0x2A,
+ 0x01, 0x2D, 0x01, 0x3C, 0x01, 0x3E, 0x01, 0x5C,
+ // Bytes 3940 - 397f
+ 0x01, 0x24, 0x01, 0x25, 0x01, 0x40, 0x03, 0x20,
+ 0xD9, 0x8B, 0x04, 0xD9, 0x80, 0xD9, 0x8B, 0x03,
+ 0x20, 0xD9, 0x8C, 0x03, 0x20, 0xD9, 0x8D, 0x03,
+ 0x20, 0xD9, 0x8E, 0x04, 0xD9, 0x80, 0xD9, 0x8E,
+ 0x03, 0x20, 0xD9, 0x8F, 0x04, 0xD9, 0x80, 0xD9,
+ 0x8F, 0x03, 0x20, 0xD9, 0x90, 0x04, 0xD9, 0x80,
+ 0xD9, 0x90, 0x03, 0x20, 0xD9, 0x91, 0x04, 0xD9,
+ 0x80, 0xD9, 0x91, 0x03, 0x20, 0xD9, 0x92, 0x04,
+ // Bytes 3980 - 39bf
+ 0xD9, 0x80, 0xD9, 0x92, 0x02, 0xD8, 0xA1, 0x02,
+ 0xD8, 0xA7, 0x02, 0xD8, 0xA8, 0x02, 0xD8, 0xA9,
+ 0x02, 0xD8, 0xAA, 0x02, 0xD8, 0xAB, 0x02, 0xD8,
+ 0xAC, 0x02, 0xD8, 0xAD, 0x02, 0xD8, 0xAE, 0x02,
+ 0xD8, 0xAF, 0x02, 0xD8, 0xB0, 0x02, 0xD8, 0xB1,
+ 0x02, 0xD8, 0xB2, 0x02, 0xD8, 0xB3, 0x02, 0xD8,
+ 0xB4, 0x02, 0xD8, 0xB5, 0x02, 0xD8, 0xB6, 0x02,
+ 0xD8, 0xB7, 0x02, 0xD8, 0xB8, 0x02, 0xD8, 0xB9,
+ // Bytes 39c0 - 39ff
+ 0x02, 0xD8, 0xBA, 0x02, 0xD9, 0x81, 0x02, 0xD9,
+ 0x82, 0x02, 0xD9, 0x83, 0x02, 0xD9, 0x84, 0x02,
+ 0xD9, 0x85, 0x02, 0xD9, 0x86, 0x02, 0xD9, 0x87,
+ 0x02, 0xD9, 0x88, 0x02, 0xD9, 0x8A, 0x06, 0xD9,
+ 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0x06, 0xD9, 0x84,
+ 0xD8, 0xA7, 0xD9, 0x94, 0x06, 0xD9, 0x84, 0xD8,
+ 0xA7, 0xD9, 0x95, 0x04, 0xD9, 0x84, 0xD8, 0xA7,
+ 0x01, 0x22, 0x01, 0x27, 0x01, 0x2F, 0x01, 0x5E,
+ // Bytes 3a00 - 3a3f
+ 0x01, 0x7C, 0x01, 0x7E, 0x03, 0xE2, 0xA6, 0x85,
+ 0x03, 0xE2, 0xA6, 0x86, 0x03, 0xE3, 0x83, 0xBB,
+ 0x03, 0xE3, 0x82, 0xA1, 0x03, 0xE3, 0x82, 0xA3,
+ 0x03, 0xE3, 0x82, 0xA5, 0x03, 0xE3, 0x82, 0xA7,
+ 0x03, 0xE3, 0x82, 0xA9, 0x03, 0xE3, 0x83, 0xA3,
+ 0x03, 0xE3, 0x83, 0xA5, 0x03, 0xE3, 0x83, 0xA7,
+ 0x03, 0xE3, 0x83, 0x83, 0x03, 0xE3, 0x83, 0xBC,
+ 0x03, 0xE3, 0x83, 0xB3, 0x03, 0xE3, 0x82, 0x99,
+ // Bytes 3a40 - 3a7f
+ 0x03, 0xE3, 0x82, 0x9A, 0x02, 0xC2, 0xA2, 0x02,
+ 0xC2, 0xA3, 0x02, 0xC2, 0xAC, 0x02, 0xC2, 0xA6,
+ 0x02, 0xC2, 0xA5, 0x03, 0xE2, 0x82, 0xA9, 0x03,
+ 0xE2, 0x94, 0x82, 0x03, 0xE2, 0x86, 0x90, 0x03,
+ 0xE2, 0x86, 0x91, 0x03, 0xE2, 0x86, 0x92, 0x03,
+ 0xE2, 0x86, 0x93, 0x03, 0xE2, 0x96, 0xA0, 0x03,
+ 0xE2, 0x97, 0x8B, 0x08, 0xF0, 0x91, 0x82, 0x99,
+ 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0, 0x91, 0x82,
+ // Bytes 3a80 - 3abf
+ 0x9B, 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0, 0x91,
+ 0x82, 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0,
+ 0x9D, 0x85, 0x97, 0xF0, 0x9D, 0x85, 0xA5, 0x08,
+ 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5,
+ 0x0C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
+ 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x0C, 0xF0, 0x9D,
+ 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D,
+ 0x85, 0xAF, 0x0C, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
+ // Bytes 3ac0 - 3aff
+ 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB0, 0x0C,
+ 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5,
+ 0xF0, 0x9D, 0x85, 0xB1, 0x0C, 0xF0, 0x9D, 0x85,
+ 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+ 0xB2, 0x08, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D,
+ 0x85, 0xA5, 0x08, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
+ 0x9D, 0x85, 0xA5, 0x0C, 0xF0, 0x9D, 0x86, 0xB9,
+ 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE,
+ // Bytes 3b00 - 3b3f
+ 0x0C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
+ 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x0C, 0xF0, 0x9D,
+ 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D,
+ 0x85, 0xAF, 0x0C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
+ 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x02,
+ 0xC4, 0xB1, 0x02, 0xC8, 0xB7, 0x02, 0xCE, 0x91,
+ 0x02, 0xCE, 0x92, 0x02, 0xCE, 0x94, 0x02, 0xCE,
+ 0x95, 0x02, 0xCE, 0x96, 0x02, 0xCE, 0x97, 0x02,
+ // Bytes 3b40 - 3b7f
+ 0xCE, 0x99, 0x02, 0xCE, 0x9A, 0x02, 0xCE, 0x9B,
+ 0x02, 0xCE, 0x9C, 0x02, 0xCE, 0x9D, 0x02, 0xCE,
+ 0x9E, 0x02, 0xCE, 0x9F, 0x02, 0xCE, 0xA1, 0x02,
+ 0xCE, 0xA4, 0x02, 0xCE, 0xA6, 0x02, 0xCE, 0xA7,
+ 0x02, 0xCE, 0xA8, 0x03, 0xE2, 0x88, 0x87, 0x02,
+ 0xCE, 0xB1, 0x02, 0xCE, 0xB6, 0x02, 0xCE, 0xB7,
+ 0x02, 0xCE, 0xBB, 0x02, 0xCE, 0xBD, 0x02, 0xCE,
+ 0xBE, 0x02, 0xCE, 0xBF, 0x02, 0xCF, 0x83, 0x02,
+ // Bytes 3b80 - 3bbf
+ 0xCF, 0x84, 0x02, 0xCF, 0x85, 0x02, 0xCF, 0x88,
+ 0x02, 0xCF, 0x89, 0x03, 0xE2, 0x88, 0x82, 0x02,
+ 0xCF, 0x9C, 0x02, 0xCF, 0x9D, 0x02, 0x30, 0x2E,
+ 0x02, 0x30, 0x2C, 0x02, 0x31, 0x2C, 0x02, 0x32,
+ 0x2C, 0x02, 0x33, 0x2C, 0x02, 0x34, 0x2C, 0x02,
+ 0x35, 0x2C, 0x02, 0x36, 0x2C, 0x02, 0x37, 0x2C,
+ 0x02, 0x38, 0x2C, 0x02, 0x39, 0x2C, 0x03, 0x28,
+ 0x41, 0x29, 0x03, 0x28, 0x42, 0x29, 0x03, 0x28,
+ // Bytes 3bc0 - 3bff
+ 0x43, 0x29, 0x03, 0x28, 0x44, 0x29, 0x03, 0x28,
+ 0x45, 0x29, 0x03, 0x28, 0x46, 0x29, 0x03, 0x28,
+ 0x47, 0x29, 0x03, 0x28, 0x48, 0x29, 0x03, 0x28,
+ 0x49, 0x29, 0x03, 0x28, 0x4A, 0x29, 0x03, 0x28,
+ 0x4B, 0x29, 0x03, 0x28, 0x4C, 0x29, 0x03, 0x28,
+ 0x4D, 0x29, 0x03, 0x28, 0x4E, 0x29, 0x03, 0x28,
+ 0x4F, 0x29, 0x03, 0x28, 0x50, 0x29, 0x03, 0x28,
+ 0x51, 0x29, 0x03, 0x28, 0x52, 0x29, 0x03, 0x28,
+ // Bytes 3c00 - 3c3f
+ 0x53, 0x29, 0x03, 0x28, 0x54, 0x29, 0x03, 0x28,
+ 0x55, 0x29, 0x03, 0x28, 0x56, 0x29, 0x03, 0x28,
+ 0x57, 0x29, 0x03, 0x28, 0x58, 0x29, 0x03, 0x28,
+ 0x59, 0x29, 0x03, 0x28, 0x5A, 0x29, 0x07, 0xE3,
+ 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x02, 0x43,
+ 0x44, 0x02, 0x57, 0x5A, 0x02, 0x48, 0x56, 0x02,
+ 0x53, 0x44, 0x02, 0x53, 0x53, 0x03, 0x50, 0x50,
+ 0x56, 0x02, 0x57, 0x43, 0x02, 0x44, 0x4A, 0x06,
+ // Bytes 3c40 - 3c7f
+ 0xE3, 0x81, 0xBB, 0xE3, 0x81, 0x8B, 0x06, 0xE3,
+ 0x82, 0xB3, 0xE3, 0x82, 0xB3, 0x03, 0xE5, 0xAD,
+ 0x97, 0x03, 0xE5, 0x8F, 0x8C, 0x03, 0xE5, 0xA4,
+ 0x9A, 0x03, 0xE8, 0xA7, 0xA3, 0x03, 0xE4, 0xBA,
+ 0xA4, 0x03, 0xE6, 0x98, 0xA0, 0x03, 0xE7, 0x84,
+ 0xA1, 0x03, 0xE5, 0x89, 0x8D, 0x03, 0xE5, 0xBE,
+ 0x8C, 0x03, 0xE5, 0x86, 0x8D, 0x03, 0xE6, 0x96,
+ 0xB0, 0x03, 0xE5, 0x88, 0x9D, 0x03, 0xE7, 0xB5,
+ // Bytes 3c80 - 3cbf
+ 0x82, 0x03, 0xE8, 0xB2, 0xA9, 0x03, 0xE5, 0xA3,
+ 0xB0, 0x03, 0xE5, 0x90, 0xB9, 0x03, 0xE6, 0xBC,
+ 0x94, 0x03, 0xE6, 0x8A, 0x95, 0x03, 0xE6, 0x8D,
+ 0x95, 0x03, 0xE9, 0x81, 0x8A, 0x03, 0xE6, 0x8C,
+ 0x87, 0x03, 0xE6, 0x89, 0x93, 0x03, 0xE7, 0xA6,
+ 0x81, 0x03, 0xE7, 0xA9, 0xBA, 0x03, 0xE5, 0x90,
+ 0x88, 0x03, 0xE6, 0xBA, 0x80, 0x03, 0xE7, 0x94,
+ 0xB3, 0x03, 0xE5, 0x89, 0xB2, 0x03, 0xE5, 0x96,
+ // Bytes 3cc0 - 3cff
+ 0xB6, 0x09, 0xE3, 0x80, 0x94, 0xE6, 0x9C, 0xAC,
+ 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE4,
+ 0xB8, 0x89, 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80,
+ 0x94, 0xE4, 0xBA, 0x8C, 0xE3, 0x80, 0x95, 0x09,
+ 0xE3, 0x80, 0x94, 0xE5, 0xAE, 0x89, 0xE3, 0x80,
+ 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE7, 0x82, 0xB9,
+ 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE6,
+ 0x89, 0x93, 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80,
+ // Bytes 3d00 - 3d3f
+ 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95, 0x09,
+ 0xE3, 0x80, 0x94, 0xE5, 0x8B, 0x9D, 0xE3, 0x80,
+ 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97,
+ 0xE3, 0x80, 0x95, 0x03, 0xE5, 0xBE, 0x97, 0x03,
+ 0xE5, 0x8F, 0xAF, 0x03, 0xE4, 0xB8, 0xBD, 0x03,
+ 0xE4, 0xB8, 0xB8, 0x03, 0xE4, 0xB9, 0x81, 0x04,
+ 0xF0, 0xA0, 0x84, 0xA2, 0x03, 0xE4, 0xBD, 0xA0,
+ 0x03, 0xE4, 0xBE, 0xBB, 0x03, 0xE5, 0x80, 0x82,
+ // Bytes 3d40 - 3d7f
+ 0x03, 0xE5, 0x81, 0xBA, 0x03, 0xE5, 0x82, 0x99,
+ 0x03, 0xE5, 0x83, 0x8F, 0x03, 0xE3, 0x92, 0x9E,
+ 0x04, 0xF0, 0xA0, 0x98, 0xBA, 0x03, 0xE5, 0x85,
+ 0x94, 0x03, 0xE5, 0x85, 0xA4, 0x03, 0xE5, 0x85,
+ 0xB7, 0x04, 0xF0, 0xA0, 0x94, 0x9C, 0x03, 0xE3,
+ 0x92, 0xB9, 0x03, 0xE5, 0x85, 0xA7, 0x04, 0xF0,
+ 0xA0, 0x95, 0x8B, 0x03, 0xE5, 0x86, 0x97, 0x03,
+ 0xE5, 0x86, 0xA4, 0x03, 0xE4, 0xBB, 0x8C, 0x03,
+ // Bytes 3d80 - 3dbf
+ 0xE5, 0x86, 0xAC, 0x04, 0xF0, 0xA9, 0x87, 0x9F,
+ 0x03, 0xE5, 0x88, 0x83, 0x03, 0xE3, 0x93, 0x9F,
+ 0x03, 0xE5, 0x88, 0xBB, 0x03, 0xE5, 0x89, 0x86,
+ 0x03, 0xE5, 0x89, 0xB7, 0x03, 0xE3, 0x94, 0x95,
+ 0x03, 0xE5, 0x8C, 0x85, 0x03, 0xE5, 0x8C, 0x86,
+ 0x03, 0xE5, 0x8D, 0x89, 0x03, 0xE5, 0x8D, 0x9A,
+ 0x03, 0xE5, 0x8D, 0xB3, 0x03, 0xE5, 0x8D, 0xBD,
+ 0x03, 0xE5, 0x8D, 0xBF, 0x04, 0xF0, 0xA0, 0xA8,
+ // Bytes 3dc0 - 3dff
+ 0xAC, 0x03, 0xE7, 0x81, 0xB0, 0x03, 0xE5, 0x8F,
+ 0x8A, 0x03, 0xE5, 0x8F, 0x9F, 0x04, 0xF0, 0xA0,
+ 0xAD, 0xA3, 0x03, 0xE5, 0x8F, 0xAB, 0x03, 0xE5,
+ 0x8F, 0xB1, 0x03, 0xE5, 0x90, 0x86, 0x03, 0xE5,
+ 0x92, 0x9E, 0x03, 0xE5, 0x90, 0xB8, 0x03, 0xE5,
+ 0x91, 0x88, 0x03, 0xE5, 0x91, 0xA8, 0x03, 0xE5,
+ 0x92, 0xA2, 0x03, 0xE5, 0x93, 0xB6, 0x03, 0xE5,
+ 0x94, 0x90, 0x03, 0xE5, 0x95, 0x93, 0x03, 0xE5,
+ // Bytes 3e00 - 3e3f
+ 0x95, 0xA3, 0x03, 0xE5, 0x96, 0x84, 0x03, 0xE5,
+ 0x96, 0xAB, 0x03, 0xE5, 0x96, 0xB3, 0x03, 0xE5,
+ 0x97, 0x82, 0x03, 0xE5, 0x9C, 0x96, 0x03, 0xE5,
+ 0x9C, 0x97, 0x03, 0xE5, 0x99, 0x91, 0x03, 0xE5,
+ 0x99, 0xB4, 0x03, 0xE5, 0xA3, 0xAE, 0x03, 0xE5,
+ 0x9F, 0x8E, 0x03, 0xE5, 0x9F, 0xB4, 0x03, 0xE5,
+ 0xA0, 0x8D, 0x03, 0xE5, 0x9E, 0x8B, 0x03, 0xE5,
+ 0xA0, 0xB2, 0x03, 0xE5, 0xA0, 0xB1, 0x03, 0xE5,
+ // Bytes 3e40 - 3e7f
+ 0xA2, 0xAC, 0x04, 0xF0, 0xA1, 0x93, 0xA4, 0x03,
+ 0xE5, 0xA3, 0xB2, 0x03, 0xE5, 0xA3, 0xB7, 0x03,
+ 0xE5, 0xA4, 0x86, 0x03, 0xE5, 0xA4, 0xA2, 0x03,
+ 0xE5, 0xA5, 0xA2, 0x04, 0xF0, 0xA1, 0x9A, 0xA8,
+ 0x04, 0xF0, 0xA1, 0x9B, 0xAA, 0x03, 0xE5, 0xA7,
+ 0xAC, 0x03, 0xE5, 0xA8, 0x9B, 0x03, 0xE5, 0xA8,
+ 0xA7, 0x03, 0xE5, 0xA7, 0x98, 0x03, 0xE5, 0xA9,
+ 0xA6, 0x03, 0xE3, 0x9B, 0xAE, 0x03, 0xE3, 0x9B,
+ // Bytes 3e80 - 3ebf
+ 0xBC, 0x03, 0xE5, 0xAC, 0x88, 0x03, 0xE5, 0xAC,
+ 0xBE, 0x04, 0xF0, 0xA1, 0xA7, 0x88, 0x03, 0xE5,
+ 0xAF, 0x83, 0x03, 0xE5, 0xAF, 0x98, 0x03, 0xE5,
+ 0xAF, 0xB3, 0x04, 0xF0, 0xA1, 0xAC, 0x98, 0x03,
+ 0xE5, 0xAF, 0xBF, 0x03, 0xE5, 0xB0, 0x86, 0x03,
+ 0xE5, 0xBD, 0x93, 0x03, 0xE3, 0x9E, 0x81, 0x03,
+ 0xE5, 0xB1, 0xA0, 0x03, 0xE5, 0xB3, 0x80, 0x03,
+ 0xE5, 0xB2, 0x8D, 0x04, 0xF0, 0xA1, 0xB7, 0xA4,
+ // Bytes 3ec0 - 3eff
+ 0x03, 0xE5, 0xB5, 0x83, 0x04, 0xF0, 0xA1, 0xB7,
+ 0xA6, 0x03, 0xE5, 0xB5, 0xAE, 0x03, 0xE5, 0xB5,
+ 0xAB, 0x03, 0xE5, 0xB5, 0xBC, 0x03, 0xE5, 0xB7,
+ 0xA1, 0x03, 0xE5, 0xB7, 0xA2, 0x03, 0xE3, 0xA0,
+ 0xAF, 0x03, 0xE5, 0xB7, 0xBD, 0x03, 0xE5, 0xB8,
+ 0xA8, 0x03, 0xE5, 0xB8, 0xBD, 0x03, 0xE5, 0xB9,
+ 0xA9, 0x03, 0xE3, 0xA1, 0xA2, 0x04, 0xF0, 0xA2,
+ 0x86, 0x83, 0x03, 0xE3, 0xA1, 0xBC, 0x03, 0xE5,
+ // Bytes 3f00 - 3f3f
+ 0xBA, 0xB0, 0x03, 0xE5, 0xBA, 0xB3, 0x03, 0xE5,
+ 0xBA, 0xB6, 0x04, 0xF0, 0xAA, 0x8E, 0x92, 0x04,
+ 0xF0, 0xA2, 0x8C, 0xB1, 0x03, 0xE8, 0x88, 0x81,
+ 0x03, 0xE5, 0xBC, 0xA2, 0x03, 0xE3, 0xA3, 0x87,
+ 0x04, 0xF0, 0xA3, 0x8A, 0xB8, 0x04, 0xF0, 0xA6,
+ 0x87, 0x9A, 0x03, 0xE5, 0xBD, 0xA2, 0x03, 0xE5,
+ 0xBD, 0xAB, 0x03, 0xE3, 0xA3, 0xA3, 0x03, 0xE5,
+ 0xBE, 0x9A, 0x03, 0xE5, 0xBF, 0x8D, 0x03, 0xE5,
+ // Bytes 3f40 - 3f7f
+ 0xBF, 0x97, 0x03, 0xE5, 0xBF, 0xB9, 0x03, 0xE6,
+ 0x82, 0x81, 0x03, 0xE3, 0xA4, 0xBA, 0x03, 0xE3,
+ 0xA4, 0x9C, 0x04, 0xF0, 0xA2, 0x9B, 0x94, 0x03,
+ 0xE6, 0x83, 0x87, 0x03, 0xE6, 0x85, 0x88, 0x03,
+ 0xE6, 0x85, 0x8C, 0x03, 0xE6, 0x85, 0xBA, 0x03,
+ 0xE6, 0x86, 0xB2, 0x03, 0xE6, 0x86, 0xA4, 0x03,
+ 0xE6, 0x86, 0xAF, 0x03, 0xE6, 0x87, 0x9E, 0x03,
+ 0xE6, 0x88, 0x90, 0x03, 0xE6, 0x88, 0x9B, 0x03,
+ // Bytes 3f80 - 3fbf
+ 0xE6, 0x89, 0x9D, 0x03, 0xE6, 0x8A, 0xB1, 0x03,
+ 0xE6, 0x8B, 0x94, 0x03, 0xE6, 0x8D, 0x90, 0x04,
+ 0xF0, 0xA2, 0xAC, 0x8C, 0x03, 0xE6, 0x8C, 0xBD,
+ 0x03, 0xE6, 0x8B, 0xBC, 0x03, 0xE6, 0x8D, 0xA8,
+ 0x03, 0xE6, 0x8E, 0x83, 0x03, 0xE6, 0x8F, 0xA4,
+ 0x04, 0xF0, 0xA2, 0xAF, 0xB1, 0x03, 0xE6, 0x90,
+ 0xA2, 0x03, 0xE6, 0x8F, 0x85, 0x03, 0xE6, 0x8E,
+ 0xA9, 0x03, 0xE3, 0xA8, 0xAE, 0x03, 0xE6, 0x91,
+ // Bytes 3fc0 - 3fff
+ 0xA9, 0x03, 0xE6, 0x91, 0xBE, 0x03, 0xE6, 0x92,
+ 0x9D, 0x03, 0xE6, 0x91, 0xB7, 0x03, 0xE3, 0xA9,
+ 0xAC, 0x03, 0xE6, 0x95, 0xAC, 0x04, 0xF0, 0xA3,
+ 0x80, 0x8A, 0x03, 0xE6, 0x97, 0xA3, 0x03, 0xE6,
+ 0x9B, 0xB8, 0x03, 0xE6, 0x99, 0x89, 0x03, 0xE3,
+ 0xAC, 0x99, 0x03, 0xE3, 0xAC, 0x88, 0x03, 0xE3,
+ 0xAB, 0xA4, 0x03, 0xE5, 0x86, 0x92, 0x03, 0xE5,
+ 0x86, 0x95, 0x03, 0xE6, 0x9C, 0x80, 0x03, 0xE6,
+ // Bytes 4000 - 403f
+ 0x9A, 0x9C, 0x03, 0xE8, 0x82, 0xAD, 0x03, 0xE4,
+ 0x8F, 0x99, 0x03, 0xE6, 0x9C, 0xA1, 0x03, 0xE6,
+ 0x9D, 0x9E, 0x03, 0xE6, 0x9D, 0x93, 0x04, 0xF0,
+ 0xA3, 0x8F, 0x83, 0x03, 0xE3, 0xAD, 0x89, 0x03,
+ 0xE6, 0x9F, 0xBA, 0x03, 0xE6, 0x9E, 0x85, 0x03,
+ 0xE6, 0xA1, 0x92, 0x04, 0xF0, 0xA3, 0x91, 0xAD,
+ 0x03, 0xE6, 0xA2, 0x8E, 0x03, 0xE6, 0xA0, 0x9F,
+ 0x03, 0xE6, 0xA4, 0x94, 0x03, 0xE6, 0xA5, 0x82,
+ // Bytes 4040 - 407f
+ 0x03, 0xE6, 0xA6, 0xA3, 0x03, 0xE6, 0xA7, 0xAA,
+ 0x03, 0xE6, 0xAA, 0xA8, 0x04, 0xF0, 0xA3, 0x9A,
+ 0xA3, 0x03, 0xE6, 0xAB, 0x9B, 0x03, 0xE3, 0xB0,
+ 0x98, 0x03, 0xE6, 0xAC, 0xA1, 0x04, 0xF0, 0xA3,
+ 0xA2, 0xA7, 0x03, 0xE6, 0xAD, 0x94, 0x03, 0xE3,
+ 0xB1, 0x8E, 0x03, 0xE6, 0xAD, 0xB2, 0x03, 0xE6,
+ 0xAE, 0x9F, 0x03, 0xE6, 0xAE, 0xBB, 0x04, 0xF0,
+ 0xA3, 0xAA, 0x8D, 0x04, 0xF0, 0xA1, 0xB4, 0x8B,
+ // Bytes 4080 - 40bf
+ 0x04, 0xF0, 0xA3, 0xAB, 0xBA, 0x03, 0xE6, 0xB1,
+ 0x8E, 0x04, 0xF0, 0xA3, 0xB2, 0xBC, 0x03, 0xE6,
+ 0xB2, 0xBF, 0x03, 0xE6, 0xB3, 0x8D, 0x03, 0xE6,
+ 0xB1, 0xA7, 0x03, 0xE6, 0xB4, 0x96, 0x03, 0xE6,
+ 0xB4, 0xBE, 0x03, 0xE6, 0xB5, 0xA9, 0x03, 0xE6,
+ 0xB5, 0xB8, 0x03, 0xE6, 0xB6, 0x85, 0x04, 0xF0,
+ 0xA3, 0xB4, 0x9E, 0x03, 0xE6, 0xB4, 0xB4, 0x03,
+ 0xE6, 0xB8, 0xAF, 0x03, 0xE6, 0xB9, 0xAE, 0x03,
+ // Bytes 40c0 - 40ff
+ 0xE3, 0xB4, 0xB3, 0x03, 0xE6, 0xBB, 0x87, 0x04,
+ 0xF0, 0xA3, 0xBB, 0x91, 0x03, 0xE6, 0xB7, 0xB9,
+ 0x03, 0xE6, 0xBD, 0xAE, 0x04, 0xF0, 0xA3, 0xBD,
+ 0x9E, 0x04, 0xF0, 0xA3, 0xBE, 0x8E, 0x03, 0xE6,
+ 0xBF, 0x86, 0x03, 0xE7, 0x80, 0xB9, 0x03, 0xE7,
+ 0x80, 0x9B, 0x03, 0xE3, 0xB6, 0x96, 0x03, 0xE7,
+ 0x81, 0x8A, 0x03, 0xE7, 0x81, 0xBD, 0x03, 0xE7,
+ 0x81, 0xB7, 0x03, 0xE7, 0x82, 0xAD, 0x04, 0xF0,
+ // Bytes 4100 - 413f
+ 0xA0, 0x94, 0xA5, 0x03, 0xE7, 0x85, 0x85, 0x04,
+ 0xF0, 0xA4, 0x89, 0xA3, 0x03, 0xE7, 0x86, 0x9C,
+ 0x04, 0xF0, 0xA4, 0x8E, 0xAB, 0x03, 0xE7, 0x88,
+ 0xA8, 0x03, 0xE7, 0x89, 0x90, 0x04, 0xF0, 0xA4,
+ 0x98, 0x88, 0x03, 0xE7, 0x8A, 0x80, 0x03, 0xE7,
+ 0x8A, 0x95, 0x04, 0xF0, 0xA4, 0x9C, 0xB5, 0x04,
+ 0xF0, 0xA4, 0xA0, 0x94, 0x03, 0xE7, 0x8D, 0xBA,
+ 0x03, 0xE7, 0x8E, 0x8B, 0x03, 0xE3, 0xBA, 0xAC,
+ // Bytes 4140 - 417f
+ 0x03, 0xE7, 0x8E, 0xA5, 0x03, 0xE3, 0xBA, 0xB8,
+ 0x03, 0xE7, 0x91, 0x87, 0x03, 0xE7, 0x91, 0x9C,
+ 0x03, 0xE7, 0x92, 0x85, 0x03, 0xE7, 0x93, 0x8A,
+ 0x03, 0xE3, 0xBC, 0x9B, 0x03, 0xE7, 0x94, 0xA4,
+ 0x04, 0xF0, 0xA4, 0xB0, 0xB6, 0x03, 0xE7, 0x94,
+ 0xBE, 0x04, 0xF0, 0xA4, 0xB2, 0x92, 0x04, 0xF0,
+ 0xA2, 0x86, 0x9F, 0x03, 0xE7, 0x98, 0x90, 0x04,
+ 0xF0, 0xA4, 0xBE, 0xA1, 0x04, 0xF0, 0xA4, 0xBE,
+ // Bytes 4180 - 41bf
+ 0xB8, 0x04, 0xF0, 0xA5, 0x81, 0x84, 0x03, 0xE3,
+ 0xBF, 0xBC, 0x03, 0xE4, 0x80, 0x88, 0x04, 0xF0,
+ 0xA5, 0x83, 0xB3, 0x04, 0xF0, 0xA5, 0x83, 0xB2,
+ 0x04, 0xF0, 0xA5, 0x84, 0x99, 0x04, 0xF0, 0xA5,
+ 0x84, 0xB3, 0x03, 0xE7, 0x9C, 0x9E, 0x03, 0xE7,
+ 0x9C, 0x9F, 0x03, 0xE7, 0x9E, 0x8B, 0x03, 0xE4,
+ 0x81, 0x86, 0x03, 0xE4, 0x82, 0x96, 0x04, 0xF0,
+ 0xA5, 0x90, 0x9D, 0x03, 0xE7, 0xA1, 0x8E, 0x03,
+ // Bytes 41c0 - 41ff
+ 0xE4, 0x83, 0xA3, 0x04, 0xF0, 0xA5, 0x98, 0xA6,
+ 0x04, 0xF0, 0xA5, 0x9A, 0x9A, 0x04, 0xF0, 0xA5,
+ 0x9B, 0x85, 0x03, 0xE7, 0xA7, 0xAB, 0x03, 0xE4,
+ 0x84, 0xAF, 0x03, 0xE7, 0xA9, 0x8A, 0x03, 0xE7,
+ 0xA9, 0x8F, 0x04, 0xF0, 0xA5, 0xA5, 0xBC, 0x04,
+ 0xF0, 0xA5, 0xAA, 0xA7, 0x03, 0xE7, 0xAB, 0xAE,
+ 0x03, 0xE4, 0x88, 0x82, 0x04, 0xF0, 0xA5, 0xAE,
+ 0xAB, 0x03, 0xE7, 0xAF, 0x86, 0x03, 0xE7, 0xAF,
+ // Bytes 4200 - 423f
+ 0x89, 0x03, 0xE4, 0x88, 0xA7, 0x04, 0xF0, 0xA5,
+ 0xB2, 0x80, 0x03, 0xE7, 0xB3, 0x92, 0x03, 0xE4,
+ 0x8A, 0xA0, 0x03, 0xE7, 0xB3, 0xA8, 0x03, 0xE7,
+ 0xB3, 0xA3, 0x03, 0xE7, 0xB4, 0x80, 0x04, 0xF0,
+ 0xA5, 0xBE, 0x86, 0x03, 0xE7, 0xB5, 0xA3, 0x03,
+ 0xE4, 0x8C, 0x81, 0x03, 0xE7, 0xB7, 0x87, 0x03,
+ 0xE7, 0xB8, 0x82, 0x03, 0xE7, 0xB9, 0x85, 0x03,
+ 0xE4, 0x8C, 0xB4, 0x04, 0xF0, 0xA6, 0x88, 0xA8,
+ // Bytes 4240 - 427f
+ 0x04, 0xF0, 0xA6, 0x89, 0x87, 0x03, 0xE4, 0x8D,
+ 0x99, 0x04, 0xF0, 0xA6, 0x8B, 0x99, 0x03, 0xE7,
+ 0xBD, 0xBA, 0x04, 0xF0, 0xA6, 0x8C, 0xBE, 0x03,
+ 0xE7, 0xBE, 0x95, 0x03, 0xE7, 0xBF, 0xBA, 0x04,
+ 0xF0, 0xA6, 0x93, 0x9A, 0x04, 0xF0, 0xA6, 0x94,
+ 0xA3, 0x03, 0xE8, 0x81, 0xA0, 0x04, 0xF0, 0xA6,
+ 0x96, 0xA8, 0x03, 0xE8, 0x81, 0xB0, 0x04, 0xF0,
+ 0xA3, 0x8D, 0x9F, 0x03, 0xE4, 0x8F, 0x95, 0x03,
+ // Bytes 4280 - 42bf
+ 0xE8, 0x82, 0xB2, 0x03, 0xE8, 0x84, 0x83, 0x03,
+ 0xE4, 0x90, 0x8B, 0x03, 0xE8, 0x84, 0xBE, 0x03,
+ 0xE5, 0xAA, 0xB5, 0x04, 0xF0, 0xA6, 0x9E, 0xA7,
+ 0x04, 0xF0, 0xA6, 0x9E, 0xB5, 0x04, 0xF0, 0xA3,
+ 0x8E, 0x93, 0x04, 0xF0, 0xA3, 0x8E, 0x9C, 0x03,
+ 0xE8, 0x88, 0x84, 0x03, 0xE8, 0xBE, 0x9E, 0x03,
+ 0xE4, 0x91, 0xAB, 0x03, 0xE8, 0x8A, 0x91, 0x03,
+ 0xE8, 0x8A, 0x8B, 0x03, 0xE8, 0x8A, 0x9D, 0x03,
+ // Bytes 42c0 - 42ff
+ 0xE5, 0x8A, 0xB3, 0x03, 0xE8, 0x8A, 0xB1, 0x03,
+ 0xE8, 0x8A, 0xB3, 0x03, 0xE8, 0x8A, 0xBD, 0x03,
+ 0xE8, 0x8B, 0xA6, 0x04, 0xF0, 0xA6, 0xAC, 0xBC,
+ 0x03, 0xE8, 0x8C, 0x9D, 0x03, 0xE8, 0x8D, 0xA3,
+ 0x03, 0xE8, 0x8E, 0xAD, 0x03, 0xE8, 0x8C, 0xA3,
+ 0x03, 0xE8, 0x8E, 0xBD, 0x03, 0xE8, 0x8F, 0xA7,
+ 0x03, 0xE8, 0x8D, 0x93, 0x03, 0xE8, 0x8F, 0x8A,
+ 0x03, 0xE8, 0x8F, 0x8C, 0x03, 0xE8, 0x8F, 0x9C,
+ // Bytes 4300 - 433f
+ 0x04, 0xF0, 0xA6, 0xB0, 0xB6, 0x04, 0xF0, 0xA6,
+ 0xB5, 0xAB, 0x04, 0xF0, 0xA6, 0xB3, 0x95, 0x03,
+ 0xE4, 0x94, 0xAB, 0x03, 0xE8, 0x93, 0xB1, 0x03,
+ 0xE8, 0x93, 0xB3, 0x03, 0xE8, 0x94, 0x96, 0x04,
+ 0xF0, 0xA7, 0x8F, 0x8A, 0x03, 0xE8, 0x95, 0xA4,
+ 0x04, 0xF0, 0xA6, 0xBC, 0xAC, 0x03, 0xE4, 0x95,
+ 0x9D, 0x03, 0xE4, 0x95, 0xA1, 0x04, 0xF0, 0xA6,
+ 0xBE, 0xB1, 0x04, 0xF0, 0xA7, 0x83, 0x92, 0x03,
+ // Bytes 4340 - 437f
+ 0xE4, 0x95, 0xAB, 0x03, 0xE8, 0x99, 0x90, 0x03,
+ 0xE8, 0x99, 0xA7, 0x03, 0xE8, 0x99, 0xA9, 0x03,
+ 0xE8, 0x9A, 0xA9, 0x03, 0xE8, 0x9A, 0x88, 0x03,
+ 0xE8, 0x9C, 0x8E, 0x03, 0xE8, 0x9B, 0xA2, 0x03,
+ 0xE8, 0x9C, 0xA8, 0x03, 0xE8, 0x9D, 0xAB, 0x03,
+ 0xE8, 0x9E, 0x86, 0x03, 0xE4, 0x97, 0x97, 0x03,
+ 0xE8, 0x9F, 0xA1, 0x03, 0xE8, 0xA0, 0x81, 0x03,
+ 0xE4, 0x97, 0xB9, 0x03, 0xE8, 0xA1, 0xA0, 0x04,
+ // Bytes 4380 - 43bf
+ 0xF0, 0xA7, 0x99, 0xA7, 0x03, 0xE8, 0xA3, 0x97,
+ 0x03, 0xE8, 0xA3, 0x9E, 0x03, 0xE4, 0x98, 0xB5,
+ 0x03, 0xE8, 0xA3, 0xBA, 0x03, 0xE3, 0x92, 0xBB,
+ 0x04, 0xF0, 0xA7, 0xA2, 0xAE, 0x04, 0xF0, 0xA7,
+ 0xA5, 0xA6, 0x03, 0xE4, 0x9A, 0xBE, 0x03, 0xE4,
+ 0x9B, 0x87, 0x03, 0xE8, 0xAA, 0xA0, 0x04, 0xF0,
+ 0xA7, 0xB2, 0xA8, 0x03, 0xE8, 0xB2, 0xAB, 0x03,
+ 0xE8, 0xB3, 0x81, 0x03, 0xE8, 0xB4, 0x9B, 0x03,
+ // Bytes 43c0 - 43ff
+ 0xE8, 0xB5, 0xB7, 0x04, 0xF0, 0xA7, 0xBC, 0xAF,
+ 0x04, 0xF0, 0xA0, 0xA0, 0x84, 0x03, 0xE8, 0xB7,
+ 0x8B, 0x03, 0xE8, 0xB6, 0xBC, 0x03, 0xE8, 0xB7,
+ 0xB0, 0x04, 0xF0, 0xA0, 0xA3, 0x9E, 0x03, 0xE8,
+ 0xBB, 0x94, 0x04, 0xF0, 0xA8, 0x97, 0x92, 0x04,
+ 0xF0, 0xA8, 0x97, 0xAD, 0x03, 0xE9, 0x82, 0x94,
+ 0x03, 0xE9, 0x83, 0xB1, 0x03, 0xE9, 0x84, 0x91,
+ 0x04, 0xF0, 0xA8, 0x9C, 0xAE, 0x03, 0xE9, 0x84,
+ // Bytes 4400 - 443f
+ 0x9B, 0x03, 0xE9, 0x88, 0xB8, 0x03, 0xE9, 0x8B,
+ 0x97, 0x03, 0xE9, 0x8B, 0x98, 0x03, 0xE9, 0x89,
+ 0xBC, 0x03, 0xE9, 0x8F, 0xB9, 0x03, 0xE9, 0x90,
+ 0x95, 0x04, 0xF0, 0xA8, 0xAF, 0xBA, 0x03, 0xE9,
+ 0x96, 0x8B, 0x03, 0xE4, 0xA6, 0x95, 0x03, 0xE9,
+ 0x96, 0xB7, 0x04, 0xF0, 0xA8, 0xB5, 0xB7, 0x03,
+ 0xE4, 0xA7, 0xA6, 0x03, 0xE9, 0x9B, 0x83, 0x03,
+ 0xE5, 0xB6, 0xB2, 0x03, 0xE9, 0x9C, 0xA3, 0x04,
+ // Bytes 4440 - 447f
+ 0xF0, 0xA9, 0x85, 0x85, 0x04, 0xF0, 0xA9, 0x88,
+ 0x9A, 0x03, 0xE4, 0xA9, 0xAE, 0x03, 0xE4, 0xA9,
+ 0xB6, 0x03, 0xE9, 0x9F, 0xA0, 0x04, 0xF0, 0xA9,
+ 0x90, 0x8A, 0x03, 0xE4, 0xAA, 0xB2, 0x04, 0xF0,
+ 0xA9, 0x92, 0x96, 0x03, 0xE9, 0xA0, 0xA9, 0x04,
+ 0xF0, 0xA9, 0x96, 0xB6, 0x03, 0xE9, 0xA3, 0xA2,
+ 0x03, 0xE4, 0xAC, 0xB3, 0x03, 0xE9, 0xA4, 0xA9,
+ 0x03, 0xE9, 0xA6, 0xA7, 0x03, 0xE9, 0xA7, 0x82,
+ // Bytes 4480 - 44bf
+ 0x03, 0xE9, 0xA7, 0xBE, 0x03, 0xE4, 0xAF, 0x8E,
+ 0x04, 0xF0, 0xA9, 0xAC, 0xB0, 0x03, 0xE9, 0xB1,
+ 0x80, 0x03, 0xE9, 0xB3, 0xBD, 0x03, 0xE4, 0xB3,
+ 0x8E, 0x03, 0xE4, 0xB3, 0xAD, 0x03, 0xE9, 0xB5,
+ 0xA7, 0x04, 0xF0, 0xAA, 0x83, 0x8E, 0x03, 0xE4,
+ 0xB3, 0xB8, 0x04, 0xF0, 0xAA, 0x84, 0x85, 0x04,
+ 0xF0, 0xAA, 0x88, 0x8E, 0x04, 0xF0, 0xAA, 0x8A,
+ 0x91, 0x03, 0xE4, 0xB5, 0x96, 0x03, 0xE9, 0xBB,
+ // Bytes 44c0 - 44ff
+ 0xBE, 0x03, 0xE9, 0xBC, 0x85, 0x03, 0xE9, 0xBC,
+ 0x8F, 0x03, 0xE9, 0xBC, 0x96, 0x04, 0xF0, 0xAA,
+ 0x98, 0x80,
+}
+
+// nfcDecompValues: 4992 entries, 9984 bytes
+// Block 2 is the null block.
+var nfcDecompValues = [4992]uint16{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x00c0: 0x0032, 0x00c1: 0x0036, 0x00c2: 0x003a, 0x00c3: 0x003e, 0x00c4: 0x0042, 0x00c5: 0x0046,
+ 0x00c7: 0x004a, 0x00c8: 0x004e, 0x00c9: 0x0052, 0x00ca: 0x0056, 0x00cb: 0x005a,
+ 0x00cc: 0x005e, 0x00cd: 0x0062, 0x00ce: 0x0066, 0x00cf: 0x006a, 0x00d1: 0x006e,
+ 0x00d2: 0x0072, 0x00d3: 0x0076, 0x00d4: 0x007a, 0x00d5: 0x007e, 0x00d6: 0x0082,
+ 0x00d9: 0x0086, 0x00da: 0x008a, 0x00db: 0x008e, 0x00dc: 0x0092, 0x00dd: 0x0096,
+ 0x00e0: 0x009a, 0x00e1: 0x009e, 0x00e2: 0x00a2, 0x00e3: 0x00a6,
+ 0x00e4: 0x00aa, 0x00e5: 0x00ae, 0x00e7: 0x00b2, 0x00e8: 0x00b6, 0x00e9: 0x00ba,
+ 0x00ea: 0x00be, 0x00eb: 0x00c2, 0x00ec: 0x00c6, 0x00ed: 0x00ca, 0x00ee: 0x00ce, 0x00ef: 0x00d2,
+ 0x00f1: 0x00d6, 0x00f2: 0x00da, 0x00f3: 0x00de, 0x00f4: 0x00e2, 0x00f5: 0x00e6,
+ 0x00f6: 0x00ea, 0x00f9: 0x00ee, 0x00fa: 0x00f2, 0x00fb: 0x00f6,
+ 0x00fc: 0x00fa, 0x00fd: 0x00fe, 0x00ff: 0x0102,
+ // Block 0x4, offset 0x100
+ 0x0100: 0x0106, 0x0101: 0x010a, 0x0102: 0x010e, 0x0103: 0x0112, 0x0104: 0x0116, 0x0105: 0x011a,
+ 0x0106: 0x011e, 0x0107: 0x0122, 0x0108: 0x0126, 0x0109: 0x012a, 0x010a: 0x012e, 0x010b: 0x0132,
+ 0x010c: 0x0136, 0x010d: 0x013a, 0x010e: 0x013e, 0x010f: 0x0142,
+ 0x0112: 0x0146, 0x0113: 0x014a, 0x0114: 0x014e, 0x0115: 0x0152, 0x0116: 0x0156, 0x0117: 0x015a,
+ 0x0118: 0x015e, 0x0119: 0x0162, 0x011a: 0x0166, 0x011b: 0x016a, 0x011c: 0x016e, 0x011d: 0x0172,
+ 0x011e: 0x0176, 0x011f: 0x017a, 0x0120: 0x017e, 0x0121: 0x0182, 0x0122: 0x0186, 0x0123: 0x018a,
+ 0x0124: 0x018e, 0x0125: 0x0192, 0x0128: 0x0196, 0x0129: 0x019a,
+ 0x012a: 0x019e, 0x012b: 0x01a2, 0x012c: 0x01a6, 0x012d: 0x01aa, 0x012e: 0x01ae, 0x012f: 0x01b2,
+ 0x0130: 0x01b6, 0x0134: 0x01c0, 0x0135: 0x01c4,
+ 0x0136: 0x01c8, 0x0137: 0x01cc, 0x0139: 0x01d0, 0x013a: 0x01d4, 0x013b: 0x01d8,
+ 0x013c: 0x01dc, 0x013d: 0x01e0, 0x013e: 0x01e4,
+ // Block 0x5, offset 0x140
+ 0x0143: 0x01f0, 0x0144: 0x01f4, 0x0145: 0x01f8,
+ 0x0146: 0x01fc, 0x0147: 0x0200, 0x0148: 0x0204,
+ 0x014c: 0x020c, 0x014d: 0x0210, 0x014e: 0x0214, 0x014f: 0x0218, 0x0150: 0x021c, 0x0151: 0x0220,
+ 0x0154: 0x0224, 0x0155: 0x0228, 0x0156: 0x022c, 0x0157: 0x0230,
+ 0x0158: 0x0234, 0x0159: 0x0238, 0x015a: 0x023c, 0x015b: 0x0240, 0x015c: 0x0244, 0x015d: 0x0248,
+ 0x015e: 0x024c, 0x015f: 0x0250, 0x0160: 0x0254, 0x0161: 0x0258, 0x0162: 0x025c, 0x0163: 0x0260,
+ 0x0164: 0x0264, 0x0165: 0x0268, 0x0168: 0x026c, 0x0169: 0x0270,
+ 0x016a: 0x0274, 0x016b: 0x0278, 0x016c: 0x027c, 0x016d: 0x0280, 0x016e: 0x0284, 0x016f: 0x0288,
+ 0x0170: 0x028c, 0x0171: 0x0290, 0x0172: 0x0294, 0x0173: 0x0298, 0x0174: 0x029c, 0x0175: 0x02a0,
+ 0x0176: 0x02a4, 0x0177: 0x02a8, 0x0178: 0x02ac, 0x0179: 0x02b0, 0x017a: 0x02b4, 0x017b: 0x02b8,
+ 0x017c: 0x02bc, 0x017d: 0x02c0, 0x017e: 0x02c4,
+ // Block 0x6, offset 0x180
+ 0x01a0: 0x02ca, 0x01a1: 0x02ce,
+ 0x01af: 0x02d2,
+ 0x01b0: 0x02d6,
+ // Block 0x7, offset 0x1c0
+ 0x01cd: 0x02fb, 0x01ce: 0x02ff, 0x01cf: 0x0303, 0x01d0: 0x0307, 0x01d1: 0x030b,
+ 0x01d2: 0x030f, 0x01d3: 0x0313, 0x01d4: 0x0317, 0x01d5: 0x031b, 0x01d6: 0x0321, 0x01d7: 0x0327,
+ 0x01d8: 0x032d, 0x01d9: 0x0333, 0x01da: 0x0339, 0x01db: 0x033f, 0x01dc: 0x0345,
+ 0x01de: 0x034b, 0x01df: 0x0351, 0x01e0: 0x0357, 0x01e1: 0x035d, 0x01e2: 0x0363, 0x01e3: 0x0368,
+ 0x01e6: 0x036d, 0x01e7: 0x0371, 0x01e8: 0x0375, 0x01e9: 0x0379,
+ 0x01ea: 0x037d, 0x01eb: 0x0381, 0x01ec: 0x0385, 0x01ed: 0x038b, 0x01ee: 0x0391, 0x01ef: 0x0396,
+ 0x01f0: 0x039b, 0x01f4: 0x03a8, 0x01f5: 0x03ac,
+ 0x01f8: 0x03b0, 0x01f9: 0x03b4, 0x01fa: 0x03b8, 0x01fb: 0x03be,
+ 0x01fc: 0x03c4, 0x01fd: 0x03c9, 0x01fe: 0x03ce, 0x01ff: 0x03d3,
+ // Block 0x8, offset 0x200
+ 0x0200: 0x03d8, 0x0201: 0x03dc, 0x0202: 0x03e0, 0x0203: 0x03e4, 0x0204: 0x03e8, 0x0205: 0x03ec,
+ 0x0206: 0x03f0, 0x0207: 0x03f4, 0x0208: 0x03f8, 0x0209: 0x03fc, 0x020a: 0x0400, 0x020b: 0x0404,
+ 0x020c: 0x0408, 0x020d: 0x040c, 0x020e: 0x0410, 0x020f: 0x0414, 0x0210: 0x0418, 0x0211: 0x041c,
+ 0x0212: 0x0420, 0x0213: 0x0424, 0x0214: 0x0428, 0x0215: 0x042c, 0x0216: 0x0430, 0x0217: 0x0434,
+ 0x0218: 0x0438, 0x0219: 0x043c, 0x021a: 0x0440, 0x021b: 0x0444,
+ 0x021e: 0x0448, 0x021f: 0x044c,
+ 0x0226: 0x0450, 0x0227: 0x0454, 0x0228: 0x0458, 0x0229: 0x045c,
+ 0x022a: 0x0460, 0x022b: 0x0466, 0x022c: 0x046c, 0x022d: 0x0472, 0x022e: 0x0478, 0x022f: 0x047c,
+ 0x0230: 0x0480, 0x0231: 0x0486, 0x0232: 0x048c, 0x0233: 0x0490,
+ // Block 0x9, offset 0x240
+ 0x0240: 0x04cc, 0x0241: 0x04cf, 0x0243: 0x04d2, 0x0244: 0x04d5,
+ 0x0274: 0x04da,
+ 0x027e: 0x04e1,
+ // Block 0xa, offset 0x280
+ 0x0285: 0x04e3,
+ 0x0286: 0x04ee, 0x0287: 0x04f3, 0x0288: 0x04f6, 0x0289: 0x04fb, 0x028a: 0x0500,
+ 0x028c: 0x0505, 0x028e: 0x050a, 0x028f: 0x050f, 0x0290: 0x0514,
+ 0x02aa: 0x051b, 0x02ab: 0x0520, 0x02ac: 0x0525, 0x02ad: 0x052a, 0x02ae: 0x052f, 0x02af: 0x0534,
+ 0x02b0: 0x0539,
+ // Block 0xb, offset 0x2c0
+ 0x02ca: 0x0540, 0x02cb: 0x0545,
+ 0x02cc: 0x054a, 0x02cd: 0x054f, 0x02ce: 0x0554,
+ 0x02d3: 0x0562, 0x02d4: 0x0567,
+ // Block 0xc, offset 0x300
+ 0x0300: 0x0584, 0x0301: 0x0589, 0x0303: 0x058e,
+ 0x0307: 0x0593,
+ 0x030c: 0x0598, 0x030d: 0x059d, 0x030e: 0x05a2,
+ 0x0319: 0x05a7,
+ 0x0339: 0x05ac,
+ // Block 0xd, offset 0x340
+ 0x0350: 0x05b1, 0x0351: 0x05b6,
+ 0x0353: 0x05bb, 0x0357: 0x05c0,
+ 0x035c: 0x05c5, 0x035d: 0x05ca,
+ 0x035e: 0x05cf,
+ 0x0376: 0x05d4, 0x0377: 0x05d9,
+ // Block 0xe, offset 0x380
+ 0x0381: 0x05de, 0x0382: 0x05e3,
+ 0x0390: 0x05e8, 0x0391: 0x05ed,
+ 0x0392: 0x05f2, 0x0393: 0x05f7, 0x0396: 0x05fc, 0x0397: 0x0601,
+ 0x039a: 0x0606, 0x039b: 0x060b, 0x039c: 0x0610, 0x039d: 0x0615,
+ 0x039e: 0x061a, 0x039f: 0x061f, 0x03a2: 0x0624, 0x03a3: 0x0629,
+ 0x03a4: 0x062e, 0x03a5: 0x0633, 0x03a6: 0x0638, 0x03a7: 0x063d,
+ 0x03aa: 0x0642, 0x03ab: 0x0647, 0x03ac: 0x064c, 0x03ad: 0x0651, 0x03ae: 0x0656, 0x03af: 0x065b,
+ 0x03b0: 0x0660, 0x03b1: 0x0665, 0x03b2: 0x066a, 0x03b3: 0x066f, 0x03b4: 0x0674, 0x03b5: 0x0679,
+ 0x03b8: 0x067e, 0x03b9: 0x0683,
+ // Block 0xf, offset 0x3c0
+ 0x03e2: 0x068d, 0x03e3: 0x0692,
+ 0x03e4: 0x0697, 0x03e5: 0x069c, 0x03e6: 0x06a1,
+ // Block 0x10, offset 0x400
+ 0x0400: 0x06ba, 0x0402: 0x06bf,
+ 0x0413: 0x06c4,
+ // Block 0x11, offset 0x440
+ 0x0469: 0x06c9,
+ 0x0471: 0x06d0, 0x0474: 0x06d7,
+ // Block 0x12, offset 0x480
+ 0x0498: 0x06de, 0x0499: 0x06e5, 0x049a: 0x06ec, 0x049b: 0x06f3, 0x049c: 0x06fa, 0x049d: 0x0701,
+ 0x049e: 0x0708, 0x049f: 0x070f,
+ // Block 0x13, offset 0x4c0
+ 0x04cb: 0x0716,
+ 0x04cc: 0x071d,
+ 0x04dc: 0x0724, 0x04dd: 0x072b,
+ 0x04df: 0x0732,
+ // Block 0x14, offset 0x500
+ 0x0533: 0x0739,
+ 0x0536: 0x0740,
+ // Block 0x15, offset 0x540
+ 0x0559: 0x0747, 0x055a: 0x074e, 0x055b: 0x0755,
+ 0x055e: 0x075c,
+ // Block 0x16, offset 0x580
+ 0x0588: 0x0763, 0x058b: 0x076a,
+ 0x058c: 0x0771,
+ 0x059c: 0x0778, 0x059d: 0x077f,
+ // Block 0x17, offset 0x5c0
+ 0x05d4: 0x0786,
+ // Block 0x18, offset 0x600
+ 0x060a: 0x078d, 0x060b: 0x0794,
+ 0x060c: 0x079b,
+ // Block 0x19, offset 0x640
+ 0x0648: 0x07a2,
+ // Block 0x1a, offset 0x680
+ 0x0680: 0x07a9,
+ 0x0687: 0x07b0, 0x0688: 0x07b7, 0x068a: 0x07be, 0x068b: 0x07c5,
+ // Block 0x1b, offset 0x6c0
+ 0x06ca: 0x07cf, 0x06cb: 0x07d6,
+ 0x06cc: 0x07dd,
+ // Block 0x1c, offset 0x700
+ 0x071a: 0x07e4, 0x071c: 0x07eb, 0x071d: 0x07f2,
+ 0x071e: 0x07fc,
+ // Block 0x1d, offset 0x740
+ 0x0743: 0x0823,
+ 0x074d: 0x082a,
+ 0x0752: 0x0831, 0x0757: 0x0838,
+ 0x075c: 0x083f,
+ 0x0769: 0x0846,
+ 0x0773: 0x084d, 0x0775: 0x0854,
+ 0x0776: 0x085b, 0x0778: 0x086c,
+ // Block 0x1e, offset 0x780
+ 0x0781: 0x087d,
+ 0x0793: 0x0884,
+ 0x079d: 0x088b,
+ 0x07a2: 0x0892,
+ 0x07a7: 0x0899,
+ 0x07ac: 0x08a0,
+ 0x07b9: 0x08a7,
+ // Block 0x1f, offset 0x7c0
+ 0x07e6: 0x08ae,
+ // Block 0x20, offset 0x800
+ 0x0806: 0x08b9, 0x0808: 0x08c0, 0x080a: 0x08c7,
+ 0x080c: 0x08ce, 0x080e: 0x08d5,
+ 0x0812: 0x08dc,
+ 0x083b: 0x08e3,
+ 0x083d: 0x08ea,
+ // Block 0x21, offset 0x840
+ 0x0840: 0x08f1, 0x0841: 0x08f8, 0x0843: 0x08ff,
+ // Block 0x22, offset 0x880
+ 0x0880: 0x09ea, 0x0881: 0x09ee, 0x0882: 0x09f2, 0x0883: 0x09f6, 0x0884: 0x09fa, 0x0885: 0x09fe,
+ 0x0886: 0x0a02, 0x0887: 0x0a06, 0x0888: 0x0a0a, 0x0889: 0x0a10, 0x088a: 0x0a16, 0x088b: 0x0a1a,
+ 0x088c: 0x0a1e, 0x088d: 0x0a22, 0x088e: 0x0a26, 0x088f: 0x0a2a, 0x0890: 0x0a2e, 0x0891: 0x0a32,
+ 0x0892: 0x0a36, 0x0893: 0x0a3a, 0x0894: 0x0a3e, 0x0895: 0x0a44, 0x0896: 0x0a4a, 0x0897: 0x0a50,
+ 0x0898: 0x0a56, 0x0899: 0x0a5a, 0x089a: 0x0a5e, 0x089b: 0x0a62, 0x089c: 0x0a66, 0x089d: 0x0a6c,
+ 0x089e: 0x0a72, 0x089f: 0x0a76, 0x08a0: 0x0a7a, 0x08a1: 0x0a7e, 0x08a2: 0x0a82, 0x08a3: 0x0a86,
+ 0x08a4: 0x0a8a, 0x08a5: 0x0a8e, 0x08a6: 0x0a92, 0x08a7: 0x0a96, 0x08a8: 0x0a9a, 0x08a9: 0x0a9e,
+ 0x08aa: 0x0aa2, 0x08ab: 0x0aa6, 0x08ac: 0x0aaa, 0x08ad: 0x0aae, 0x08ae: 0x0ab2, 0x08af: 0x0ab8,
+ 0x08b0: 0x0abe, 0x08b1: 0x0ac2, 0x08b2: 0x0ac6, 0x08b3: 0x0aca, 0x08b4: 0x0ace, 0x08b5: 0x0ad2,
+ 0x08b6: 0x0ad6, 0x08b7: 0x0ada, 0x08b8: 0x0ade, 0x08b9: 0x0ae4, 0x08ba: 0x0aea, 0x08bb: 0x0aee,
+ 0x08bc: 0x0af2, 0x08bd: 0x0af6, 0x08be: 0x0afa, 0x08bf: 0x0afe,
+ // Block 0x23, offset 0x8c0
+ 0x08c0: 0x0b02, 0x08c1: 0x0b06, 0x08c2: 0x0b0a, 0x08c3: 0x0b0e, 0x08c4: 0x0b12, 0x08c5: 0x0b16,
+ 0x08c6: 0x0b1a, 0x08c7: 0x0b1e, 0x08c8: 0x0b22, 0x08c9: 0x0b26, 0x08ca: 0x0b2a, 0x08cb: 0x0b2e,
+ 0x08cc: 0x0b32, 0x08cd: 0x0b38, 0x08ce: 0x0b3e, 0x08cf: 0x0b44, 0x08d0: 0x0b4a, 0x08d1: 0x0b50,
+ 0x08d2: 0x0b56, 0x08d3: 0x0b5c, 0x08d4: 0x0b62, 0x08d5: 0x0b66, 0x08d6: 0x0b6a, 0x08d7: 0x0b6e,
+ 0x08d8: 0x0b72, 0x08d9: 0x0b76, 0x08da: 0x0b7a, 0x08db: 0x0b7e, 0x08dc: 0x0b82, 0x08dd: 0x0b88,
+ 0x08de: 0x0b8e, 0x08df: 0x0b92, 0x08e0: 0x0b96, 0x08e1: 0x0b9a, 0x08e2: 0x0b9e, 0x08e3: 0x0ba2,
+ 0x08e4: 0x0ba6, 0x08e5: 0x0bac, 0x08e6: 0x0bb2, 0x08e7: 0x0bb8, 0x08e8: 0x0bbe, 0x08e9: 0x0bc4,
+ 0x08ea: 0x0bca, 0x08eb: 0x0bce, 0x08ec: 0x0bd2, 0x08ed: 0x0bd6, 0x08ee: 0x0bda, 0x08ef: 0x0bde,
+ 0x08f0: 0x0be2, 0x08f1: 0x0be6, 0x08f2: 0x0bea, 0x08f3: 0x0bee, 0x08f4: 0x0bf2, 0x08f5: 0x0bf6,
+ 0x08f6: 0x0bfa, 0x08f7: 0x0bfe, 0x08f8: 0x0c02, 0x08f9: 0x0c08, 0x08fa: 0x0c0e, 0x08fb: 0x0c14,
+ 0x08fc: 0x0c1a, 0x08fd: 0x0c1e, 0x08fe: 0x0c22, 0x08ff: 0x0c26,
+ // Block 0x24, offset 0x900
+ 0x0900: 0x0c2a, 0x0901: 0x0c2e, 0x0902: 0x0c32, 0x0903: 0x0c36, 0x0904: 0x0c3a, 0x0905: 0x0c3e,
+ 0x0906: 0x0c42, 0x0907: 0x0c46, 0x0908: 0x0c4a, 0x0909: 0x0c4e, 0x090a: 0x0c52, 0x090b: 0x0c56,
+ 0x090c: 0x0c5a, 0x090d: 0x0c5e, 0x090e: 0x0c62, 0x090f: 0x0c66, 0x0910: 0x0c6a, 0x0911: 0x0c6e,
+ 0x0912: 0x0c72, 0x0913: 0x0c76, 0x0914: 0x0c7a, 0x0915: 0x0c7e, 0x0916: 0x0c82, 0x0917: 0x0c86,
+ 0x0918: 0x0c8a, 0x0919: 0x0c8e, 0x091b: 0x0c96,
+ 0x0920: 0x0c9b, 0x0921: 0x0c9f, 0x0922: 0x0ca3, 0x0923: 0x0ca7,
+ 0x0924: 0x0cab, 0x0925: 0x0cb1, 0x0926: 0x0cb7, 0x0927: 0x0cbd, 0x0928: 0x0cc3, 0x0929: 0x0cc9,
+ 0x092a: 0x0ccf, 0x092b: 0x0cd5, 0x092c: 0x0cdb, 0x092d: 0x0ce1, 0x092e: 0x0ce7, 0x092f: 0x0ced,
+ 0x0930: 0x0cf3, 0x0931: 0x0cf9, 0x0932: 0x0cff, 0x0933: 0x0d05, 0x0934: 0x0d0b, 0x0935: 0x0d11,
+ 0x0936: 0x0d17, 0x0937: 0x0d1d, 0x0938: 0x0d23, 0x0939: 0x0d27, 0x093a: 0x0d2b, 0x093b: 0x0d2f,
+ 0x093c: 0x0d33, 0x093d: 0x0d37, 0x093e: 0x0d3b, 0x093f: 0x0d41,
+ // Block 0x25, offset 0x940
+ 0x0940: 0x0d47, 0x0941: 0x0d4d, 0x0942: 0x0d53, 0x0943: 0x0d59, 0x0944: 0x0d5f, 0x0945: 0x0d65,
+ 0x0946: 0x0d6b, 0x0947: 0x0d71, 0x0948: 0x0d77, 0x0949: 0x0d7b, 0x094a: 0x0d7f, 0x094b: 0x0d83,
+ 0x094c: 0x0d87, 0x094d: 0x0d8b, 0x094e: 0x0d8f, 0x094f: 0x0d93, 0x0950: 0x0d97, 0x0951: 0x0d9d,
+ 0x0952: 0x0da3, 0x0953: 0x0da9, 0x0954: 0x0daf, 0x0955: 0x0db5, 0x0956: 0x0dbb, 0x0957: 0x0dc1,
+ 0x0958: 0x0dc7, 0x0959: 0x0dcd, 0x095a: 0x0dd3, 0x095b: 0x0dd9, 0x095c: 0x0ddf, 0x095d: 0x0de5,
+ 0x095e: 0x0deb, 0x095f: 0x0df1, 0x0960: 0x0df7, 0x0961: 0x0dfd, 0x0962: 0x0e03, 0x0963: 0x0e09,
+ 0x0964: 0x0e0f, 0x0965: 0x0e13, 0x0966: 0x0e17, 0x0967: 0x0e1b, 0x0968: 0x0e1f, 0x0969: 0x0e25,
+ 0x096a: 0x0e2b, 0x096b: 0x0e31, 0x096c: 0x0e37, 0x096d: 0x0e3d, 0x096e: 0x0e43, 0x096f: 0x0e49,
+ 0x0970: 0x0e4f, 0x0971: 0x0e55, 0x0972: 0x0e5b, 0x0973: 0x0e5f, 0x0974: 0x0e63, 0x0975: 0x0e67,
+ 0x0976: 0x0e6b, 0x0977: 0x0e6f, 0x0978: 0x0e73, 0x0979: 0x0e77,
+ // Block 0x26, offset 0x980
+ 0x0980: 0x0e7b, 0x0981: 0x0e80, 0x0982: 0x0e85, 0x0983: 0x0e8c, 0x0984: 0x0e93, 0x0985: 0x0e9a,
+ 0x0986: 0x0ea1, 0x0987: 0x0ea8, 0x0988: 0x0eaf, 0x0989: 0x0eb4, 0x098a: 0x0eb9, 0x098b: 0x0ec0,
+ 0x098c: 0x0ec7, 0x098d: 0x0ece, 0x098e: 0x0ed5, 0x098f: 0x0edc, 0x0990: 0x0ee3, 0x0991: 0x0ee8,
+ 0x0992: 0x0eed, 0x0993: 0x0ef4, 0x0994: 0x0efb, 0x0995: 0x0f02,
+ 0x0998: 0x0f09, 0x0999: 0x0f0e, 0x099a: 0x0f13, 0x099b: 0x0f1a, 0x099c: 0x0f21, 0x099d: 0x0f28,
+ 0x09a0: 0x0f2f, 0x09a1: 0x0f34, 0x09a2: 0x0f39, 0x09a3: 0x0f40,
+ 0x09a4: 0x0f47, 0x09a5: 0x0f4e, 0x09a6: 0x0f55, 0x09a7: 0x0f5c, 0x09a8: 0x0f63, 0x09a9: 0x0f68,
+ 0x09aa: 0x0f6d, 0x09ab: 0x0f74, 0x09ac: 0x0f7b, 0x09ad: 0x0f82, 0x09ae: 0x0f89, 0x09af: 0x0f90,
+ 0x09b0: 0x0f97, 0x09b1: 0x0f9c, 0x09b2: 0x0fa1, 0x09b3: 0x0fa8, 0x09b4: 0x0faf, 0x09b5: 0x0fb6,
+ 0x09b6: 0x0fbd, 0x09b7: 0x0fc4, 0x09b8: 0x0fcb, 0x09b9: 0x0fd0, 0x09ba: 0x0fd5, 0x09bb: 0x0fdc,
+ 0x09bc: 0x0fe3, 0x09bd: 0x0fea, 0x09be: 0x0ff1, 0x09bf: 0x0ff8,
+ // Block 0x27, offset 0x9c0
+ 0x09c0: 0x0fff, 0x09c1: 0x1004, 0x09c2: 0x1009, 0x09c3: 0x1010, 0x09c4: 0x1017, 0x09c5: 0x101e,
+ 0x09c8: 0x1025, 0x09c9: 0x102a, 0x09ca: 0x102f, 0x09cb: 0x1036,
+ 0x09cc: 0x103d, 0x09cd: 0x1044, 0x09d0: 0x104b, 0x09d1: 0x1050,
+ 0x09d2: 0x1055, 0x09d3: 0x105c, 0x09d4: 0x1063, 0x09d5: 0x106a, 0x09d6: 0x1071, 0x09d7: 0x1078,
+ 0x09d9: 0x107f, 0x09db: 0x1084, 0x09dd: 0x108b,
+ 0x09df: 0x1092, 0x09e0: 0x1099, 0x09e1: 0x109e, 0x09e2: 0x10a3, 0x09e3: 0x10aa,
+ 0x09e4: 0x10b1, 0x09e5: 0x10b8, 0x09e6: 0x10bf, 0x09e7: 0x10c6, 0x09e8: 0x10cd, 0x09e9: 0x10d2,
+ 0x09ea: 0x10d7, 0x09eb: 0x10de, 0x09ec: 0x10e5, 0x09ed: 0x10ec, 0x09ee: 0x10f3, 0x09ef: 0x10fa,
+ 0x09f0: 0x1101, 0x09f1: 0x0525, 0x09f2: 0x1106, 0x09f3: 0x052a, 0x09f4: 0x110b, 0x09f5: 0x052f,
+ 0x09f6: 0x1110, 0x09f7: 0x0534, 0x09f8: 0x1115, 0x09f9: 0x054a, 0x09fa: 0x111a, 0x09fb: 0x054f,
+ 0x09fc: 0x111f, 0x09fd: 0x0554,
+ // Block 0x28, offset 0xa00
+ 0x0a00: 0x1124, 0x0a01: 0x112b, 0x0a02: 0x1132, 0x0a03: 0x113b, 0x0a04: 0x1144, 0x0a05: 0x114d,
+ 0x0a06: 0x1156, 0x0a07: 0x115f, 0x0a08: 0x1168, 0x0a09: 0x116f, 0x0a0a: 0x1176, 0x0a0b: 0x117f,
+ 0x0a0c: 0x1188, 0x0a0d: 0x1191, 0x0a0e: 0x119a, 0x0a0f: 0x11a3, 0x0a10: 0x11ac, 0x0a11: 0x11b3,
+ 0x0a12: 0x11ba, 0x0a13: 0x11c3, 0x0a14: 0x11cc, 0x0a15: 0x11d5, 0x0a16: 0x11de, 0x0a17: 0x11e7,
+ 0x0a18: 0x11f0, 0x0a19: 0x11f7, 0x0a1a: 0x11fe, 0x0a1b: 0x1207, 0x0a1c: 0x1210, 0x0a1d: 0x1219,
+ 0x0a1e: 0x1222, 0x0a1f: 0x122b, 0x0a20: 0x1234, 0x0a21: 0x123b, 0x0a22: 0x1242, 0x0a23: 0x124b,
+ 0x0a24: 0x1254, 0x0a25: 0x125d, 0x0a26: 0x1266, 0x0a27: 0x126f, 0x0a28: 0x1278, 0x0a29: 0x127f,
+ 0x0a2a: 0x1286, 0x0a2b: 0x128f, 0x0a2c: 0x1298, 0x0a2d: 0x12a1, 0x0a2e: 0x12aa, 0x0a2f: 0x12b3,
+ 0x0a30: 0x12bc, 0x0a31: 0x12c1, 0x0a32: 0x12c6, 0x0a33: 0x12cd, 0x0a34: 0x12d2,
+ 0x0a36: 0x12d9, 0x0a37: 0x12de, 0x0a38: 0x12e5, 0x0a39: 0x12ea, 0x0a3a: 0x12ef, 0x0a3b: 0x04ee,
+ 0x0a3c: 0x12f4, 0x0a3e: 0x12fd,
+ // Block 0x29, offset 0xa40
+ 0x0a41: 0x1304, 0x0a42: 0x130f, 0x0a43: 0x1316, 0x0a44: 0x131b,
+ 0x0a46: 0x1322, 0x0a47: 0x1327, 0x0a48: 0x132e, 0x0a49: 0x04f6, 0x0a4a: 0x1333, 0x0a4b: 0x04fb,
+ 0x0a4c: 0x1338, 0x0a4d: 0x133d, 0x0a4e: 0x1349, 0x0a4f: 0x1355, 0x0a50: 0x1361, 0x0a51: 0x1366,
+ 0x0a52: 0x136b, 0x0a53: 0x0514, 0x0a56: 0x1372, 0x0a57: 0x1377,
+ 0x0a58: 0x137e, 0x0a59: 0x1383, 0x0a5a: 0x1388, 0x0a5b: 0x0500, 0x0a5d: 0x138d,
+ 0x0a5e: 0x1399, 0x0a5f: 0x13a5, 0x0a60: 0x13b1, 0x0a61: 0x13b6, 0x0a62: 0x13bb, 0x0a63: 0x0539,
+ 0x0a64: 0x13c2, 0x0a65: 0x13c7, 0x0a66: 0x13cc, 0x0a67: 0x13d1, 0x0a68: 0x13d8, 0x0a69: 0x13dd,
+ 0x0a6a: 0x13e2, 0x0a6b: 0x050a, 0x0a6c: 0x13e7, 0x0a6d: 0x13ec, 0x0a6e: 0x04e3, 0x0a6f: 0x13f7,
+ 0x0a72: 0x13f9, 0x0a73: 0x1400, 0x0a74: 0x1405,
+ 0x0a76: 0x140c, 0x0a77: 0x1411, 0x0a78: 0x1418, 0x0a79: 0x0505, 0x0a7a: 0x141d, 0x0a7b: 0x050f,
+ 0x0a7c: 0x1422, 0x0a7d: 0x1427,
+ // Block 0x2a, offset 0xa80
+ 0x0a80: 0x142e, 0x0a81: 0x1432,
+ // Block 0x2b, offset 0xac0
+ 0x0ae6: 0x14d6,
+ 0x0aea: 0x091c, 0x0aeb: 0x0046,
+ // Block 0x2c, offset 0xb00
+ 0x0b1a: 0x159f, 0x0b1b: 0x15a5,
+ 0x0b2e: 0x15ab,
+ // Block 0x2d, offset 0xb40
+ 0x0b4d: 0x15b1, 0x0b4e: 0x15b7, 0x0b4f: 0x15bd,
+ // Block 0x2e, offset 0xb80
+ 0x0b84: 0x15c3,
+ 0x0b89: 0x15c9,
+ 0x0b8c: 0x15cf,
+ 0x0ba4: 0x15d5, 0x0ba6: 0x15db,
+ // Block 0x2f, offset 0xbc0
+ 0x0bc1: 0x1603, 0x0bc4: 0x1609,
+ 0x0bc7: 0x160f, 0x0bc9: 0x1615,
+ 0x0be0: 0x161b, 0x0be2: 0x161f,
+ 0x0bed: 0x1625, 0x0bee: 0x162b, 0x0bef: 0x162f,
+ 0x0bf0: 0x1633, 0x0bf1: 0x1639, 0x0bf4: 0x163f, 0x0bf5: 0x1645,
+ 0x0bf8: 0x164b, 0x0bf9: 0x1651,
+ // Block 0x30, offset 0xc00
+ 0x0c00: 0x1657, 0x0c01: 0x165d, 0x0c04: 0x1663, 0x0c05: 0x1669,
+ 0x0c08: 0x166f, 0x0c09: 0x1675,
+ 0x0c2c: 0x167b, 0x0c2d: 0x1681, 0x0c2e: 0x1687, 0x0c2f: 0x168d,
+ // Block 0x31, offset 0xc40
+ 0x0c60: 0x1693, 0x0c61: 0x1699, 0x0c62: 0x169f, 0x0c63: 0x16a5,
+ 0x0c6a: 0x16ab, 0x0c6b: 0x16b1, 0x0c6c: 0x16b7, 0x0c6d: 0x16bd,
+ // Block 0x32, offset 0xc80
+ 0x0ca9: 0x16c3,
+ 0x0caa: 0x16c7,
+ // Block 0x33, offset 0xcc0
+ 0x0cdc: 0x1814,
+ // Block 0x34, offset 0xd00
+ 0x0d0c: 0x1b8a, 0x0d0e: 0x1b91, 0x0d10: 0x1b98,
+ 0x0d12: 0x1b9f, 0x0d14: 0x1ba6, 0x0d16: 0x1bad,
+ 0x0d18: 0x1bb4, 0x0d1a: 0x1bbb, 0x0d1c: 0x1bc2,
+ 0x0d1e: 0x1bc9, 0x0d20: 0x1bd0, 0x0d22: 0x1bd7,
+ 0x0d25: 0x1bde, 0x0d27: 0x1be5, 0x0d29: 0x1bec,
+ 0x0d30: 0x1bf3, 0x0d31: 0x1bfa, 0x0d33: 0x1c01, 0x0d34: 0x1c08,
+ 0x0d36: 0x1c0f, 0x0d37: 0x1c16, 0x0d39: 0x1c1d, 0x0d3a: 0x1c24,
+ 0x0d3c: 0x1c2b, 0x0d3d: 0x1c32,
+ // Block 0x35, offset 0xd40
+ 0x0d54: 0x1c39,
+ 0x0d5e: 0x1c4a,
+ 0x0d6c: 0x1c58, 0x0d6e: 0x1c5f,
+ 0x0d70: 0x1c66, 0x0d72: 0x1c6d, 0x0d74: 0x1c74,
+ 0x0d76: 0x1c7b, 0x0d78: 0x1c82, 0x0d7a: 0x1c89,
+ 0x0d7c: 0x1c90, 0x0d7e: 0x1c97,
+ // Block 0x36, offset 0xd80
+ 0x0d80: 0x1c9e, 0x0d82: 0x1ca5, 0x0d85: 0x1cac,
+ 0x0d87: 0x1cb3, 0x0d89: 0x1cba,
+ 0x0d90: 0x1cc1, 0x0d91: 0x1cc8,
+ 0x0d93: 0x1ccf, 0x0d94: 0x1cd6, 0x0d96: 0x1cdd, 0x0d97: 0x1ce4,
+ 0x0d99: 0x1ceb, 0x0d9a: 0x1cf2, 0x0d9c: 0x1cf9, 0x0d9d: 0x1d00,
+ 0x0db4: 0x1d07,
+ 0x0db7: 0x1d0e, 0x0db8: 0x1d15, 0x0db9: 0x1d1c, 0x0dba: 0x1d23,
+ 0x0dbe: 0x1d2a,
+ // Block 0x37, offset 0xdc0
+ 0x0dc0: 0x2a81, 0x0dc1: 0x2a85, 0x0dc2: 0x1a9e, 0x0dc3: 0x2a89, 0x0dc4: 0x2a8d, 0x0dc5: 0x2a91,
+ 0x0dc6: 0x2a95, 0x0dc7: 0x1b76, 0x0dc8: 0x1b76, 0x0dc9: 0x2a99, 0x0dca: 0x1abe, 0x0dcb: 0x2a9d,
+ 0x0dcc: 0x2aa1, 0x0dcd: 0x2aa5, 0x0dce: 0x2aa9, 0x0dcf: 0x2aad, 0x0dd0: 0x2ab1, 0x0dd1: 0x2ab5,
+ 0x0dd2: 0x2ab9, 0x0dd3: 0x2abd, 0x0dd4: 0x2ac1, 0x0dd5: 0x2ac5, 0x0dd6: 0x2ac9, 0x0dd7: 0x2acd,
+ 0x0dd8: 0x2ad1, 0x0dd9: 0x2ad5, 0x0dda: 0x2ad9, 0x0ddb: 0x2add, 0x0ddc: 0x2ae1, 0x0ddd: 0x2ae5,
+ 0x0dde: 0x2ae9, 0x0ddf: 0x2aed, 0x0de0: 0x2af1, 0x0de1: 0x2af5, 0x0de2: 0x2af9, 0x0de3: 0x2afd,
+ 0x0de4: 0x2b01, 0x0de5: 0x2b05, 0x0de6: 0x2b09, 0x0de7: 0x2b0d, 0x0de8: 0x2b11, 0x0de9: 0x2b15,
+ 0x0dea: 0x2b19, 0x0deb: 0x2b1d, 0x0dec: 0x2b21, 0x0ded: 0x2b25, 0x0dee: 0x2b29, 0x0def: 0x2b2d,
+ 0x0df0: 0x2b31, 0x0df1: 0x2b35, 0x0df2: 0x2b39, 0x0df3: 0x2b3d, 0x0df4: 0x1a16, 0x0df5: 0x2b41,
+ 0x0df6: 0x2b45, 0x0df7: 0x2b49, 0x0df8: 0x2b4d, 0x0df9: 0x2b51, 0x0dfa: 0x2b55, 0x0dfb: 0x2b59,
+ 0x0dfc: 0x2b5d, 0x0dfd: 0x2b61, 0x0dfe: 0x2b65, 0x0dff: 0x2b69,
+ // Block 0x38, offset 0xe00
+ 0x0e00: 0x1b3a, 0x0e01: 0x2b6d, 0x0e02: 0x2b71, 0x0e03: 0x2b75, 0x0e04: 0x2b79, 0x0e05: 0x2b7d,
+ 0x0e06: 0x2b81, 0x0e07: 0x2b85, 0x0e08: 0x2b89, 0x0e09: 0x2b8d, 0x0e0a: 0x2b91, 0x0e0b: 0x2b95,
+ 0x0e0c: 0x2b99, 0x0e0d: 0x2b9d, 0x0e0e: 0x2ba1, 0x0e0f: 0x2ba5, 0x0e10: 0x2ba9, 0x0e11: 0x2bad,
+ 0x0e12: 0x2bb1, 0x0e13: 0x2bb5, 0x0e14: 0x2bb9, 0x0e15: 0x2bbd, 0x0e16: 0x2bc1, 0x0e17: 0x2bc5,
+ 0x0e18: 0x2bc9, 0x0e19: 0x2bcd, 0x0e1a: 0x2bd1, 0x0e1b: 0x2bd5, 0x0e1c: 0x2ac1, 0x0e1d: 0x2bd9,
+ 0x0e1e: 0x2bdd, 0x0e1f: 0x2be1, 0x0e20: 0x2be5, 0x0e21: 0x2be9, 0x0e22: 0x2bed, 0x0e23: 0x2bf1,
+ 0x0e24: 0x2bf5, 0x0e25: 0x2bf9, 0x0e26: 0x2bfd, 0x0e27: 0x2c01, 0x0e28: 0x2c05, 0x0e29: 0x2c09,
+ 0x0e2a: 0x2c0d, 0x0e2b: 0x2c11, 0x0e2c: 0x2c15, 0x0e2d: 0x2c19, 0x0e2e: 0x2c1d, 0x0e2f: 0x2c21,
+ 0x0e30: 0x2c25, 0x0e31: 0x1aa6, 0x0e32: 0x2c29, 0x0e33: 0x2c2d, 0x0e34: 0x2c31, 0x0e35: 0x2c35,
+ 0x0e36: 0x2c39, 0x0e37: 0x2c3d, 0x0e38: 0x2c41, 0x0e39: 0x2c45, 0x0e3a: 0x2c49, 0x0e3b: 0x2c4d,
+ 0x0e3c: 0x2c51, 0x0e3d: 0x2c55, 0x0e3e: 0x2c59, 0x0e3f: 0x2c5d,
+ // Block 0x39, offset 0xe40
+ 0x0e40: 0x2c61, 0x0e41: 0x18ba, 0x0e42: 0x2c65, 0x0e43: 0x2c69, 0x0e44: 0x2c6d, 0x0e45: 0x2c71,
+ 0x0e46: 0x2c75, 0x0e47: 0x2c79, 0x0e48: 0x2c7d, 0x0e49: 0x2c81, 0x0e4a: 0x186e, 0x0e4b: 0x2c85,
+ 0x0e4c: 0x2c89, 0x0e4d: 0x2c8d, 0x0e4e: 0x2c91, 0x0e4f: 0x2c95, 0x0e50: 0x2c99, 0x0e51: 0x2c9d,
+ 0x0e52: 0x2ca1, 0x0e53: 0x2ca5, 0x0e54: 0x2ca9, 0x0e55: 0x2cad, 0x0e56: 0x2cb1, 0x0e57: 0x2cb5,
+ 0x0e58: 0x2cb9, 0x0e59: 0x2cbd, 0x0e5a: 0x2cc1, 0x0e5b: 0x2cc5, 0x0e5c: 0x2cc9, 0x0e5d: 0x2ccd,
+ 0x0e5e: 0x2cd1, 0x0e5f: 0x2cd5, 0x0e60: 0x2cd9, 0x0e61: 0x2c21, 0x0e62: 0x2cdd, 0x0e63: 0x2ce1,
+ 0x0e64: 0x2ce5, 0x0e65: 0x2ce9, 0x0e66: 0x2ced, 0x0e67: 0x2cf1, 0x0e68: 0x2cf5, 0x0e69: 0x2cf9,
+ 0x0e6a: 0x2be1, 0x0e6b: 0x2cfd, 0x0e6c: 0x2d01, 0x0e6d: 0x2d05, 0x0e6e: 0x2d09, 0x0e6f: 0x2d0d,
+ 0x0e70: 0x2d11, 0x0e71: 0x2d15, 0x0e72: 0x2d19, 0x0e73: 0x2d1d, 0x0e74: 0x2d21, 0x0e75: 0x2d25,
+ 0x0e76: 0x2d29, 0x0e77: 0x2d2d, 0x0e78: 0x2d31, 0x0e79: 0x2d35, 0x0e7a: 0x2d39, 0x0e7b: 0x2d3d,
+ 0x0e7c: 0x2d41, 0x0e7d: 0x2d45, 0x0e7e: 0x2d49, 0x0e7f: 0x2ac1,
+ // Block 0x3a, offset 0xe80
+ 0x0e80: 0x2d4d, 0x0e81: 0x2d51, 0x0e82: 0x2d55, 0x0e83: 0x2d59, 0x0e84: 0x1b72, 0x0e85: 0x2d5d,
+ 0x0e86: 0x2d61, 0x0e87: 0x2d65, 0x0e88: 0x2d69, 0x0e89: 0x2d6d, 0x0e8a: 0x2d71, 0x0e8b: 0x2d75,
+ 0x0e8c: 0x2d79, 0x0e8d: 0x2d7d, 0x0e8e: 0x2d81, 0x0e8f: 0x2d85, 0x0e90: 0x2d89, 0x0e91: 0x2173,
+ 0x0e92: 0x2d8d, 0x0e93: 0x2d91, 0x0e94: 0x2d95, 0x0e95: 0x2d99, 0x0e96: 0x2d9d, 0x0e97: 0x2da1,
+ 0x0e98: 0x2da5, 0x0e99: 0x2da9, 0x0e9a: 0x2dad, 0x0e9b: 0x2be9, 0x0e9c: 0x2db1, 0x0e9d: 0x2db5,
+ 0x0e9e: 0x2db9, 0x0e9f: 0x2dbd, 0x0ea0: 0x2dc1, 0x0ea1: 0x2dc5, 0x0ea2: 0x2dc9, 0x0ea3: 0x2dcd,
+ 0x0ea4: 0x2dd1, 0x0ea5: 0x2dd5, 0x0ea6: 0x2dd9, 0x0ea7: 0x2ddd, 0x0ea8: 0x2de1, 0x0ea9: 0x1aba,
+ 0x0eaa: 0x2de5, 0x0eab: 0x2de9, 0x0eac: 0x2ded, 0x0ead: 0x2df1, 0x0eae: 0x2df5, 0x0eaf: 0x2df9,
+ 0x0eb0: 0x2dfd, 0x0eb1: 0x2e01, 0x0eb2: 0x2e05, 0x0eb3: 0x2e09, 0x0eb4: 0x2e0d, 0x0eb5: 0x2e11,
+ 0x0eb6: 0x2e15, 0x0eb7: 0x19f6, 0x0eb8: 0x2e19, 0x0eb9: 0x2e1d, 0x0eba: 0x2e21, 0x0ebb: 0x2e25,
+ 0x0ebc: 0x2e29, 0x0ebd: 0x2e2d, 0x0ebe: 0x2e31, 0x0ebf: 0x2e35,
+ // Block 0x3b, offset 0xec0
+ 0x0ec0: 0x2e39, 0x0ec1: 0x2e3d, 0x0ec2: 0x2e41, 0x0ec3: 0x2e45, 0x0ec4: 0x2e49, 0x0ec5: 0x2e4d,
+ 0x0ec6: 0x2e51, 0x0ec7: 0x2e55, 0x0ec8: 0x1a62, 0x0ec9: 0x2e59, 0x0eca: 0x1a6e, 0x0ecb: 0x2e5d,
+ 0x0ecc: 0x2e61, 0x0ecd: 0x2e65, 0x0ed0: 0x2e69,
+ 0x0ed2: 0x2e6d, 0x0ed5: 0x2e71, 0x0ed6: 0x2e75, 0x0ed7: 0x2e79,
+ 0x0ed8: 0x2e7d, 0x0ed9: 0x2e81, 0x0eda: 0x2e85, 0x0edb: 0x2e89, 0x0edc: 0x2e8d, 0x0edd: 0x2e91,
+ 0x0ede: 0x1a12, 0x0ee0: 0x2e95, 0x0ee2: 0x2e99,
+ 0x0ee5: 0x2e9d, 0x0ee6: 0x2ea1,
+ 0x0eea: 0x2ea5, 0x0eeb: 0x2ea9, 0x0eec: 0x2ead, 0x0eed: 0x2eb1,
+ 0x0ef0: 0x2eb5, 0x0ef1: 0x2eb9, 0x0ef2: 0x2ebd, 0x0ef3: 0x2ec1, 0x0ef4: 0x2ec5, 0x0ef5: 0x2ec9,
+ 0x0ef6: 0x2ecd, 0x0ef7: 0x2ed1, 0x0ef8: 0x2ed5, 0x0ef9: 0x2ed9, 0x0efa: 0x2edd, 0x0efb: 0x2ee1,
+ 0x0efc: 0x18d6, 0x0efd: 0x2ee5, 0x0efe: 0x2ee9, 0x0eff: 0x2eed,
+ // Block 0x3c, offset 0xf00
+ 0x0f00: 0x2ef1, 0x0f01: 0x2ef5, 0x0f02: 0x2ef9, 0x0f03: 0x2efd, 0x0f04: 0x2f01, 0x0f05: 0x2f05,
+ 0x0f06: 0x2f09, 0x0f07: 0x2f0d, 0x0f08: 0x2f11, 0x0f09: 0x2f15, 0x0f0a: 0x2f19, 0x0f0b: 0x2f1d,
+ 0x0f0c: 0x2187, 0x0f0d: 0x2f21, 0x0f0e: 0x2f25, 0x0f0f: 0x2f29, 0x0f10: 0x2f2d, 0x0f11: 0x2197,
+ 0x0f12: 0x2f31, 0x0f13: 0x2f35, 0x0f14: 0x2f39, 0x0f15: 0x2f3d, 0x0f16: 0x2f41, 0x0f17: 0x2cb1,
+ 0x0f18: 0x2f45, 0x0f19: 0x2f49, 0x0f1a: 0x2f4d, 0x0f1b: 0x2f51, 0x0f1c: 0x2f55, 0x0f1d: 0x2f59,
+ 0x0f1e: 0x2f59, 0x0f1f: 0x2f5d, 0x0f20: 0x2f61, 0x0f21: 0x2f65, 0x0f22: 0x2f69, 0x0f23: 0x2f6d,
+ 0x0f24: 0x2f71, 0x0f25: 0x2f75, 0x0f26: 0x2f79, 0x0f27: 0x2e9d, 0x0f28: 0x2f7d, 0x0f29: 0x2f81,
+ 0x0f2a: 0x2f85, 0x0f2b: 0x2f89, 0x0f2c: 0x2f8d, 0x0f2d: 0x2f92,
+ 0x0f30: 0x2f96, 0x0f31: 0x2f9a, 0x0f32: 0x2f9e, 0x0f33: 0x2fa2, 0x0f34: 0x2fa6, 0x0f35: 0x2faa,
+ 0x0f36: 0x2fae, 0x0f37: 0x2fb2, 0x0f38: 0x2ecd, 0x0f39: 0x2fb6, 0x0f3a: 0x2fba, 0x0f3b: 0x2fbe,
+ 0x0f3c: 0x2e69, 0x0f3d: 0x2fc2, 0x0f3e: 0x2fc6, 0x0f3f: 0x2fca,
+ // Block 0x3d, offset 0xf40
+ 0x0f40: 0x2fce, 0x0f41: 0x2fd2, 0x0f42: 0x2fd6, 0x0f43: 0x2fda, 0x0f44: 0x2fde, 0x0f45: 0x2fe2,
+ 0x0f46: 0x2fe6, 0x0f47: 0x2fea, 0x0f48: 0x2fee, 0x0f49: 0x2eed, 0x0f4a: 0x2ff2, 0x0f4b: 0x2ef1,
+ 0x0f4c: 0x2ff6, 0x0f4d: 0x2ffa, 0x0f4e: 0x2ffe, 0x0f4f: 0x3002, 0x0f50: 0x3006, 0x0f51: 0x2e6d,
+ 0x0f52: 0x2b15, 0x0f53: 0x300a, 0x0f54: 0x300e, 0x0f55: 0x195a, 0x0f56: 0x2c25, 0x0f57: 0x2d71,
+ 0x0f58: 0x3012, 0x0f59: 0x3016, 0x0f5a: 0x2f0d, 0x0f5b: 0x301a, 0x0f5c: 0x2f11, 0x0f5d: 0x301e,
+ 0x0f5e: 0x3022, 0x0f5f: 0x3026, 0x0f60: 0x2e75, 0x0f61: 0x302a, 0x0f62: 0x302e, 0x0f63: 0x3032,
+ 0x0f64: 0x3036, 0x0f65: 0x303a, 0x0f66: 0x2e79, 0x0f67: 0x303e, 0x0f68: 0x3042, 0x0f69: 0x3046,
+ 0x0f6a: 0x304a, 0x0f6b: 0x304e, 0x0f6c: 0x3052, 0x0f6d: 0x2f41, 0x0f6e: 0x3056, 0x0f6f: 0x305a,
+ 0x0f70: 0x2cb1, 0x0f71: 0x305e, 0x0f72: 0x2f51, 0x0f73: 0x3062, 0x0f74: 0x3066, 0x0f75: 0x306a,
+ 0x0f76: 0x306e, 0x0f77: 0x3072, 0x0f78: 0x2f65, 0x0f79: 0x3076, 0x0f7a: 0x2e99, 0x0f7b: 0x307a,
+ 0x0f7c: 0x2f69, 0x0f7d: 0x2bd9, 0x0f7e: 0x307e, 0x0f7f: 0x2f6d,
+ // Block 0x3e, offset 0xf80
+ 0x0f80: 0x3082, 0x0f81: 0x2f75, 0x0f82: 0x3086, 0x0f83: 0x308a, 0x0f84: 0x308e, 0x0f85: 0x3092,
+ 0x0f86: 0x3096, 0x0f87: 0x2f7d, 0x0f88: 0x2e8d, 0x0f89: 0x309a, 0x0f8a: 0x2f81, 0x0f8b: 0x309e,
+ 0x0f8c: 0x2f85, 0x0f8d: 0x30a2, 0x0f8e: 0x1b76, 0x0f8f: 0x30a6, 0x0f90: 0x30ab, 0x0f91: 0x30b0,
+ 0x0f92: 0x30b5, 0x0f93: 0x30b9, 0x0f94: 0x30bd, 0x0f95: 0x30c1, 0x0f96: 0x30c6, 0x0f97: 0x30cb,
+ 0x0f98: 0x30d0, 0x0f99: 0x30d4,
+ // Block 0x3f, offset 0xfc0
+ 0x0fdd: 0x3105,
+ 0x0fdf: 0x310a,
+ 0x0fea: 0x3124, 0x0feb: 0x3129, 0x0fec: 0x312e, 0x0fed: 0x3135, 0x0fee: 0x313c, 0x0fef: 0x3141,
+ 0x0ff0: 0x3146, 0x0ff1: 0x314b, 0x0ff2: 0x3150, 0x0ff3: 0x3155, 0x0ff4: 0x315a, 0x0ff5: 0x315f,
+ 0x0ff6: 0x3164, 0x0ff8: 0x3169, 0x0ff9: 0x316e, 0x0ffa: 0x3173, 0x0ffb: 0x3178,
+ 0x0ffc: 0x317d, 0x0ffe: 0x3182,
+ // Block 0x40, offset 0x1000
+ 0x1000: 0x3187, 0x1001: 0x318c, 0x1003: 0x3191, 0x1004: 0x3196,
+ 0x1006: 0x319b, 0x1007: 0x31a0, 0x1008: 0x31a5, 0x1009: 0x31aa, 0x100a: 0x31af, 0x100b: 0x31b4,
+ 0x100c: 0x31b9, 0x100d: 0x31be, 0x100e: 0x31c3,
+ // Block 0x41, offset 0x1040
+ 0x105a: 0x3a73, 0x105c: 0x3a7c,
+ 0x106b: 0x3a85,
+ // Block 0x42, offset 0x1080
+ 0x109e: 0x3a8e, 0x109f: 0x3a97, 0x10a0: 0x3aa0, 0x10a1: 0x3aad, 0x10a2: 0x3aba, 0x10a3: 0x3ac7,
+ 0x10a4: 0x3ad4,
+ // Block 0x43, offset 0x10c0
+ 0x10fb: 0x3ae1,
+ 0x10fc: 0x3aea, 0x10fd: 0x3af3, 0x10fe: 0x3b00, 0x10ff: 0x3b0d,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x3b1a,
+ // Block 0x45, offset 0x1140
+ 0x1140: 0x3d23, 0x1141: 0x3d27, 0x1142: 0x3d2b, 0x1143: 0x3d2f, 0x1144: 0x3d34, 0x1145: 0x2eb5,
+ 0x1146: 0x3d38, 0x1147: 0x3d3c, 0x1148: 0x3d40, 0x1149: 0x3d44, 0x114a: 0x2eb9, 0x114b: 0x3d48,
+ 0x114c: 0x3d4c, 0x114d: 0x3d50, 0x114e: 0x2ebd, 0x114f: 0x3d55, 0x1150: 0x3d59, 0x1151: 0x3d5d,
+ 0x1152: 0x3d61, 0x1153: 0x3d66, 0x1154: 0x3d6a, 0x1155: 0x3c71, 0x1156: 0x3d6e, 0x1157: 0x3d73,
+ 0x1158: 0x3d77, 0x1159: 0x3d7b, 0x115a: 0x3d7f, 0x115b: 0x2f9a, 0x115c: 0x3d83, 0x115d: 0x1866,
+ 0x115e: 0x3d88, 0x115f: 0x3d8c, 0x1160: 0x3d90, 0x1161: 0x3d94, 0x1162: 0x3cb9, 0x1163: 0x3d98,
+ 0x1164: 0x3d9c, 0x1165: 0x2fae, 0x1166: 0x2ec1, 0x1167: 0x2ec5, 0x1168: 0x2fb2, 0x1169: 0x3da0,
+ 0x116a: 0x3da4, 0x116b: 0x2bf1, 0x116c: 0x3da8, 0x116d: 0x2ec9, 0x116e: 0x3dac, 0x116f: 0x3db0,
+ 0x1170: 0x3db4, 0x1171: 0x3db8, 0x1172: 0x3db8, 0x1173: 0x3db8, 0x1174: 0x3dbc, 0x1175: 0x3dc1,
+ 0x1176: 0x3dc5, 0x1177: 0x3dc9, 0x1178: 0x3dcd, 0x1179: 0x3dd2, 0x117a: 0x3dd6, 0x117b: 0x3dda,
+ 0x117c: 0x3dde, 0x117d: 0x3de2, 0x117e: 0x3de6, 0x117f: 0x3dea,
+ // Block 0x46, offset 0x1180
+ 0x1180: 0x3dee, 0x1181: 0x3df2, 0x1182: 0x3df6, 0x1183: 0x3dfa, 0x1184: 0x3dfe, 0x1185: 0x3e02,
+ 0x1186: 0x3e02, 0x1187: 0x2fba, 0x1188: 0x3e06, 0x1189: 0x3e0a, 0x118a: 0x3e0e, 0x118b: 0x3e12,
+ 0x118c: 0x2ed1, 0x118d: 0x3e16, 0x118e: 0x3e1a, 0x118f: 0x3e1e, 0x1190: 0x2e39, 0x1191: 0x3e22,
+ 0x1192: 0x3e26, 0x1193: 0x3e2a, 0x1194: 0x3e2e, 0x1195: 0x3e32, 0x1196: 0x3e36, 0x1197: 0x3e3a,
+ 0x1198: 0x3e3e, 0x1199: 0x3e42, 0x119a: 0x3e47, 0x119b: 0x3e4b, 0x119c: 0x3e4f, 0x119d: 0x3c55,
+ 0x119e: 0x3e53, 0x119f: 0x3e57, 0x11a0: 0x3e5b, 0x11a1: 0x3e60, 0x11a2: 0x3e65, 0x11a3: 0x3e69,
+ 0x11a4: 0x3e6d, 0x11a5: 0x3e71, 0x11a6: 0x3e75, 0x11a7: 0x3e79, 0x11a8: 0x3e7d, 0x11a9: 0x3e81,
+ 0x11aa: 0x3e85, 0x11ab: 0x3e85, 0x11ac: 0x3e89, 0x11ad: 0x3e8e, 0x11ae: 0x3e92, 0x11af: 0x2be1,
+ 0x11b0: 0x3e96, 0x11b1: 0x3e9a, 0x11b2: 0x3e9f, 0x11b3: 0x3ea3, 0x11b4: 0x3ea7, 0x11b5: 0x18ce,
+ 0x11b6: 0x3eab, 0x11b7: 0x3eaf, 0x11b8: 0x18d6, 0x11b9: 0x3eb3, 0x11ba: 0x3eb7, 0x11bb: 0x3ebb,
+ 0x11bc: 0x3ec0, 0x11bd: 0x3ec4, 0x11be: 0x3ec9, 0x11bf: 0x3ecd,
+ // Block 0x47, offset 0x11c0
+ 0x11c0: 0x3ed1, 0x11c1: 0x3ed5, 0x11c2: 0x3ed9, 0x11c3: 0x3edd, 0x11c4: 0x3ee1, 0x11c5: 0x3ee5,
+ 0x11c6: 0x3ee9, 0x11c7: 0x3eed, 0x11c8: 0x3ef1, 0x11c9: 0x3ef5, 0x11ca: 0x3efa, 0x11cb: 0x3efe,
+ 0x11cc: 0x3f02, 0x11cd: 0x3f06, 0x11ce: 0x2b11, 0x11cf: 0x3f0a, 0x11d0: 0x18fe, 0x11d1: 0x3f0f,
+ 0x11d2: 0x3f0f, 0x11d3: 0x3f14, 0x11d4: 0x3f18, 0x11d5: 0x3f18, 0x11d6: 0x3f1c, 0x11d7: 0x3f20,
+ 0x11d8: 0x3f25, 0x11d9: 0x3f2a, 0x11da: 0x3f2e, 0x11db: 0x3f32, 0x11dc: 0x3f36, 0x11dd: 0x3f3a,
+ 0x11de: 0x3f3e, 0x11df: 0x3f42, 0x11e0: 0x3f46, 0x11e1: 0x3f4a, 0x11e2: 0x3f4e, 0x11e3: 0x2ee5,
+ 0x11e4: 0x3f52, 0x11e5: 0x3f57, 0x11e6: 0x3f5b, 0x11e7: 0x3f5f, 0x11e8: 0x2fea, 0x11e9: 0x3f5f,
+ 0x11ea: 0x3f63, 0x11eb: 0x2eed, 0x11ec: 0x3f67, 0x11ed: 0x3f6b, 0x11ee: 0x3f6f, 0x11ef: 0x3f73,
+ 0x11f0: 0x2ef1, 0x11f1: 0x2aa5, 0x11f2: 0x3f77, 0x11f3: 0x3f7b, 0x11f4: 0x3f7f, 0x11f5: 0x3f83,
+ 0x11f6: 0x3f87, 0x11f7: 0x3f8b, 0x11f8: 0x3f8f, 0x11f9: 0x3f94, 0x11fa: 0x3f98, 0x11fb: 0x3f9c,
+ 0x11fc: 0x3fa0, 0x11fd: 0x3fa4, 0x11fe: 0x3fa8, 0x11ff: 0x3fad,
+ // Block 0x48, offset 0x1200
+ 0x1200: 0x3fb1, 0x1201: 0x3fb5, 0x1202: 0x3fb9, 0x1203: 0x3fbd, 0x1204: 0x3fc1, 0x1205: 0x3fc5,
+ 0x1206: 0x3fc9, 0x1207: 0x3fcd, 0x1208: 0x2ef5, 0x1209: 0x3fd1, 0x120a: 0x3fd5, 0x120b: 0x3fda,
+ 0x120c: 0x3fde, 0x120d: 0x3fe2, 0x120e: 0x3fe6, 0x120f: 0x2efd, 0x1210: 0x3fea, 0x1211: 0x3fee,
+ 0x1212: 0x3ff2, 0x1213: 0x3ff6, 0x1214: 0x3ffa, 0x1215: 0x3ffe, 0x1216: 0x4002, 0x1217: 0x4006,
+ 0x1218: 0x2b15, 0x1219: 0x300a, 0x121a: 0x400a, 0x121b: 0x400e, 0x121c: 0x4012, 0x121d: 0x4016,
+ 0x121e: 0x401b, 0x121f: 0x401f, 0x1220: 0x4023, 0x1221: 0x4027, 0x1222: 0x2f01, 0x1223: 0x402b,
+ 0x1224: 0x4030, 0x1225: 0x4034, 0x1226: 0x4038, 0x1227: 0x30b5, 0x1228: 0x403c, 0x1229: 0x4040,
+ 0x122a: 0x4044, 0x122b: 0x4048, 0x122c: 0x404c, 0x122d: 0x4051, 0x122e: 0x4055, 0x122f: 0x4059,
+ 0x1230: 0x405d, 0x1231: 0x4062, 0x1232: 0x4066, 0x1233: 0x406a, 0x1234: 0x406e, 0x1235: 0x2c25,
+ 0x1236: 0x4072, 0x1237: 0x4076, 0x1238: 0x407b, 0x1239: 0x4080, 0x123a: 0x4085, 0x123b: 0x4089,
+ 0x123c: 0x408e, 0x123d: 0x4092, 0x123e: 0x4096, 0x123f: 0x409a,
+ // Block 0x49, offset 0x1240
+ 0x1240: 0x409e, 0x1241: 0x2f05, 0x1242: 0x2d71, 0x1243: 0x40a2, 0x1244: 0x40a6, 0x1245: 0x40aa,
+ 0x1246: 0x40ae, 0x1247: 0x40b3, 0x1248: 0x40b7, 0x1249: 0x40bb, 0x124a: 0x40bf, 0x124b: 0x3016,
+ 0x124c: 0x40c3, 0x124d: 0x40c7, 0x124e: 0x40cc, 0x124f: 0x40d0, 0x1250: 0x40d4, 0x1251: 0x40d9,
+ 0x1252: 0x40de, 0x1253: 0x40e2, 0x1254: 0x301a, 0x1255: 0x40e6, 0x1256: 0x40ea, 0x1257: 0x40ee,
+ 0x1258: 0x40f2, 0x1259: 0x40f6, 0x125a: 0x40fa, 0x125b: 0x40fe, 0x125c: 0x4103, 0x125d: 0x4107,
+ 0x125e: 0x410c, 0x125f: 0x4110, 0x1260: 0x4115, 0x1261: 0x3022, 0x1262: 0x4119, 0x1263: 0x411d,
+ 0x1264: 0x4122, 0x1265: 0x4126, 0x1266: 0x412a, 0x1267: 0x412f, 0x1268: 0x4134, 0x1269: 0x4138,
+ 0x126a: 0x413c, 0x126b: 0x4140, 0x126c: 0x4144, 0x126d: 0x4144, 0x126e: 0x4148, 0x126f: 0x414c,
+ 0x1270: 0x302a, 0x1271: 0x4150, 0x1272: 0x4154, 0x1273: 0x4158, 0x1274: 0x415c, 0x1275: 0x4160,
+ 0x1276: 0x4165, 0x1277: 0x4169, 0x1278: 0x2bed, 0x1279: 0x416e, 0x127a: 0x4173, 0x127b: 0x4177,
+ 0x127c: 0x417c, 0x127d: 0x4181, 0x127e: 0x4186, 0x127f: 0x418a,
+ // Block 0x4a, offset 0x1280
+ 0x1280: 0x3042, 0x1281: 0x418e, 0x1282: 0x4193, 0x1283: 0x4198, 0x1284: 0x419d, 0x1285: 0x41a2,
+ 0x1286: 0x41a6, 0x1287: 0x41a6, 0x1288: 0x3046, 0x1289: 0x30bd, 0x128a: 0x41aa, 0x128b: 0x41ae,
+ 0x128c: 0x41b2, 0x128d: 0x41b6, 0x128e: 0x41bb, 0x128f: 0x2b59, 0x1290: 0x304e, 0x1291: 0x41bf,
+ 0x1292: 0x41c3, 0x1293: 0x2f2d, 0x1294: 0x41c8, 0x1295: 0x41cd, 0x1296: 0x2e89, 0x1297: 0x41d2,
+ 0x1298: 0x41d6, 0x1299: 0x2f39, 0x129a: 0x41da, 0x129b: 0x41de, 0x129c: 0x41e2, 0x129d: 0x41e7,
+ 0x129e: 0x41e7, 0x129f: 0x41ec, 0x12a0: 0x41f0, 0x12a1: 0x41f4, 0x12a2: 0x41f9, 0x12a3: 0x41fd,
+ 0x12a4: 0x4201, 0x12a5: 0x4205, 0x12a6: 0x420a, 0x12a7: 0x420e, 0x12a8: 0x4212, 0x12a9: 0x4216,
+ 0x12aa: 0x421a, 0x12ab: 0x421e, 0x12ac: 0x4223, 0x12ad: 0x4227, 0x12ae: 0x422b, 0x12af: 0x422f,
+ 0x12b0: 0x4233, 0x12b1: 0x4237, 0x12b2: 0x423b, 0x12b3: 0x4240, 0x12b4: 0x4245, 0x12b5: 0x4249,
+ 0x12b6: 0x424e, 0x12b7: 0x4252, 0x12b8: 0x4257, 0x12b9: 0x425b, 0x12ba: 0x2f51, 0x12bb: 0x425f,
+ 0x12bc: 0x4264, 0x12bd: 0x4269, 0x12be: 0x426d, 0x12bf: 0x4272,
+ // Block 0x4b, offset 0x12c0
+ 0x12c0: 0x4276, 0x12c1: 0x427b, 0x12c2: 0x427f, 0x12c3: 0x4283, 0x12c4: 0x4287, 0x12c5: 0x428b,
+ 0x12c6: 0x428f, 0x12c7: 0x4293, 0x12c8: 0x4298, 0x12c9: 0x429d, 0x12ca: 0x42a2, 0x12cb: 0x3f14,
+ 0x12cc: 0x42a7, 0x12cd: 0x42ab, 0x12ce: 0x42af, 0x12cf: 0x42b3, 0x12d0: 0x42b7, 0x12d1: 0x42bb,
+ 0x12d2: 0x42bf, 0x12d3: 0x42c3, 0x12d4: 0x42c7, 0x12d5: 0x42cb, 0x12d6: 0x42cf, 0x12d7: 0x42d3,
+ 0x12d8: 0x2c31, 0x12d9: 0x42d8, 0x12da: 0x42dc, 0x12db: 0x42e0, 0x12dc: 0x42e4, 0x12dd: 0x42e8,
+ 0x12de: 0x42ec, 0x12df: 0x2f5d, 0x12e0: 0x42f0, 0x12e1: 0x42f4, 0x12e2: 0x42f8, 0x12e3: 0x42fc,
+ 0x12e4: 0x4300, 0x12e5: 0x4305, 0x12e6: 0x430a, 0x12e7: 0x430f, 0x12e8: 0x4313, 0x12e9: 0x4317,
+ 0x12ea: 0x431b, 0x12eb: 0x431f, 0x12ec: 0x4324, 0x12ed: 0x4328, 0x12ee: 0x432d, 0x12ef: 0x4331,
+ 0x12f0: 0x4335, 0x12f1: 0x433a, 0x12f2: 0x433f, 0x12f3: 0x4343, 0x12f4: 0x2b45, 0x12f5: 0x4347,
+ 0x12f6: 0x434b, 0x12f7: 0x434f, 0x12f8: 0x4353, 0x12f9: 0x4357, 0x12fa: 0x435b, 0x12fb: 0x306a,
+ 0x12fc: 0x435f, 0x12fd: 0x4363, 0x12fe: 0x4367, 0x12ff: 0x436b,
+ // Block 0x4c, offset 0x1300
+ 0x1300: 0x436f, 0x1301: 0x4373, 0x1302: 0x4377, 0x1303: 0x437b, 0x1304: 0x1a66, 0x1305: 0x437f,
+ 0x1306: 0x4384, 0x1307: 0x4388, 0x1308: 0x438c, 0x1309: 0x4390, 0x130a: 0x4394, 0x130b: 0x4398,
+ 0x130c: 0x439d, 0x130d: 0x43a2, 0x130e: 0x43a6, 0x130f: 0x43aa, 0x1310: 0x307e, 0x1311: 0x3082,
+ 0x1312: 0x1a82, 0x1313: 0x43ae, 0x1314: 0x43b3, 0x1315: 0x43b7, 0x1316: 0x43bb, 0x1317: 0x43bf,
+ 0x1318: 0x43c3, 0x1319: 0x43c8, 0x131a: 0x43cd, 0x131b: 0x43d1, 0x131c: 0x43d5, 0x131d: 0x43d9,
+ 0x131e: 0x43de, 0x131f: 0x3086, 0x1320: 0x43e2, 0x1321: 0x43e7, 0x1322: 0x43ec, 0x1323: 0x43f0,
+ 0x1324: 0x43f4, 0x1325: 0x43f8, 0x1326: 0x43fd, 0x1327: 0x4401, 0x1328: 0x4405, 0x1329: 0x4409,
+ 0x132a: 0x440d, 0x132b: 0x4411, 0x132c: 0x4415, 0x132d: 0x4419, 0x132e: 0x441e, 0x132f: 0x4422,
+ 0x1330: 0x4426, 0x1331: 0x442a, 0x1332: 0x442f, 0x1333: 0x4433, 0x1334: 0x4437, 0x1335: 0x443b,
+ 0x1336: 0x443f, 0x1337: 0x4444, 0x1338: 0x4449, 0x1339: 0x444d, 0x133a: 0x4451, 0x133b: 0x4455,
+ 0x133c: 0x445a, 0x133d: 0x445e, 0x133e: 0x309e, 0x133f: 0x309e,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x4463, 0x1341: 0x4467, 0x1342: 0x446c, 0x1343: 0x4470, 0x1344: 0x4474, 0x1345: 0x4478,
+ 0x1346: 0x447c, 0x1347: 0x4480, 0x1348: 0x4484, 0x1349: 0x4488, 0x134a: 0x30a2, 0x134b: 0x448d,
+ 0x134c: 0x4491, 0x134d: 0x4495, 0x134e: 0x4499, 0x134f: 0x449d, 0x1350: 0x44a1, 0x1351: 0x44a6,
+ 0x1352: 0x44aa, 0x1353: 0x44af, 0x1354: 0x44b4, 0x1355: 0x1b42, 0x1356: 0x44b9, 0x1357: 0x1b52,
+ 0x1358: 0x44bd, 0x1359: 0x44c1, 0x135a: 0x44c5, 0x135b: 0x44c9, 0x135c: 0x1b66, 0x135d: 0x44cd,
+}
+
+// nfcDecompLookup: 832 bytes
+// Block 0 is the null block.
+var nfcDecompLookup = [832]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x0c3: 0x03, 0x0c4: 0x04, 0x0c5: 0x05, 0x0c6: 0x06, 0x0c7: 0x07,
+ 0x0c8: 0x08, 0x0cd: 0x09, 0x0ce: 0x0a, 0x0cf: 0x0b,
+ 0x0d0: 0x0c, 0x0d1: 0x0d, 0x0d3: 0x0e,
+ 0x0d8: 0x0f, 0x0db: 0x10,
+ 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07,
+ 0x0ef: 0x08,
+ 0x0f0: 0x0c,
+ // Block 0x4, offset 0x100
+ 0x124: 0x11, 0x125: 0x12, 0x127: 0x13,
+ 0x128: 0x14, 0x129: 0x15, 0x12d: 0x16, 0x12e: 0x17, 0x12f: 0x18,
+ 0x131: 0x19, 0x133: 0x1a, 0x135: 0x1b, 0x137: 0x1c,
+ 0x13d: 0x1d, 0x13e: 0x1e,
+ // Block 0x5, offset 0x140
+ 0x140: 0x1f,
+ 0x16c: 0x20, 0x16d: 0x21,
+ 0x178: 0x22, 0x179: 0x23, 0x17a: 0x24, 0x17b: 0x25, 0x17c: 0x26, 0x17d: 0x27, 0x17e: 0x28, 0x17f: 0x29,
+ // Block 0x6, offset 0x180
+ 0x180: 0x2a, 0x184: 0x2b, 0x186: 0x2c, 0x187: 0x2d,
+ 0x188: 0x2e, 0x189: 0x2f, 0x18a: 0x30, 0x18b: 0x31, 0x18c: 0x32,
+ 0x1ab: 0x33,
+ // Block 0x7, offset 0x1c0
+ 0x1c1: 0x34, 0x1c2: 0x35, 0x1c3: 0x36,
+ // Block 0x8, offset 0x200
+ 0x224: 0x37, 0x225: 0x38, 0x226: 0x39, 0x227: 0x3a,
+ 0x228: 0x3b, 0x229: 0x3c, 0x22a: 0x3d, 0x22b: 0x3e, 0x22c: 0x3f, 0x22d: 0x40,
+ // Block 0x9, offset 0x240
+ 0x242: 0x41,
+ // Block 0xa, offset 0x280
+ 0x285: 0x42, 0x286: 0x43, 0x287: 0x44,
+ // Block 0xb, offset 0x2c0
+ 0x2e0: 0x45, 0x2e1: 0x46, 0x2e2: 0x47, 0x2e3: 0x48, 0x2e4: 0x49, 0x2e5: 0x4a, 0x2e6: 0x4b, 0x2e7: 0x4c,
+ 0x2e8: 0x4d,
+ // Block 0xc, offset 0x300
+ 0x311: 0x09,
+ 0x31d: 0x0a,
+ 0x32f: 0x0b,
+}
+
+var nfcDecompTrie = trie{nfcDecompLookup[:], nfcDecompValues[:]}
+
+// nfkcDecompValues: 10176 entries, 20352 bytes
+// Block 2 is the null block.
+var nfkcDecompValues = [10176]uint16{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x00e0: 0x0001,
+ 0x00e8: 0x0003,
+ 0x00ea: 0x0007, 0x00ef: 0x0009,
+ 0x00f2: 0x000d, 0x00f3: 0x000f, 0x00f4: 0x0011, 0x00f5: 0x0015,
+ 0x00f8: 0x0018, 0x00f9: 0x001c, 0x00fa: 0x001e,
+ 0x00fc: 0x0020, 0x00fd: 0x0026, 0x00fe: 0x002c,
+ // Block 0x4, offset 0x100
+ 0x0100: 0x0032, 0x0101: 0x0036, 0x0102: 0x003a, 0x0103: 0x003e, 0x0104: 0x0042, 0x0105: 0x0046,
+ 0x0107: 0x004a, 0x0108: 0x004e, 0x0109: 0x0052, 0x010a: 0x0056, 0x010b: 0x005a,
+ 0x010c: 0x005e, 0x010d: 0x0062, 0x010e: 0x0066, 0x010f: 0x006a, 0x0111: 0x006e,
+ 0x0112: 0x0072, 0x0113: 0x0076, 0x0114: 0x007a, 0x0115: 0x007e, 0x0116: 0x0082,
+ 0x0119: 0x0086, 0x011a: 0x008a, 0x011b: 0x008e, 0x011c: 0x0092, 0x011d: 0x0096,
+ 0x0120: 0x009a, 0x0121: 0x009e, 0x0122: 0x00a2, 0x0123: 0x00a6,
+ 0x0124: 0x00aa, 0x0125: 0x00ae, 0x0127: 0x00b2, 0x0128: 0x00b6, 0x0129: 0x00ba,
+ 0x012a: 0x00be, 0x012b: 0x00c2, 0x012c: 0x00c6, 0x012d: 0x00ca, 0x012e: 0x00ce, 0x012f: 0x00d2,
+ 0x0131: 0x00d6, 0x0132: 0x00da, 0x0133: 0x00de, 0x0134: 0x00e2, 0x0135: 0x00e6,
+ 0x0136: 0x00ea, 0x0139: 0x00ee, 0x013a: 0x00f2, 0x013b: 0x00f6,
+ 0x013c: 0x00fa, 0x013d: 0x00fe, 0x013f: 0x0102,
+ // Block 0x5, offset 0x140
+ 0x0140: 0x0106, 0x0141: 0x010a, 0x0142: 0x010e, 0x0143: 0x0112, 0x0144: 0x0116, 0x0145: 0x011a,
+ 0x0146: 0x011e, 0x0147: 0x0122, 0x0148: 0x0126, 0x0149: 0x012a, 0x014a: 0x012e, 0x014b: 0x0132,
+ 0x014c: 0x0136, 0x014d: 0x013a, 0x014e: 0x013e, 0x014f: 0x0142,
+ 0x0152: 0x0146, 0x0153: 0x014a, 0x0154: 0x014e, 0x0155: 0x0152, 0x0156: 0x0156, 0x0157: 0x015a,
+ 0x0158: 0x015e, 0x0159: 0x0162, 0x015a: 0x0166, 0x015b: 0x016a, 0x015c: 0x016e, 0x015d: 0x0172,
+ 0x015e: 0x0176, 0x015f: 0x017a, 0x0160: 0x017e, 0x0161: 0x0182, 0x0162: 0x0186, 0x0163: 0x018a,
+ 0x0164: 0x018e, 0x0165: 0x0192, 0x0168: 0x0196, 0x0169: 0x019a,
+ 0x016a: 0x019e, 0x016b: 0x01a2, 0x016c: 0x01a6, 0x016d: 0x01aa, 0x016e: 0x01ae, 0x016f: 0x01b2,
+ 0x0170: 0x01b6, 0x0172: 0x01ba, 0x0173: 0x01bd, 0x0174: 0x01c0, 0x0175: 0x01c4,
+ 0x0176: 0x01c8, 0x0177: 0x01cc, 0x0179: 0x01d0, 0x017a: 0x01d4, 0x017b: 0x01d8,
+ 0x017c: 0x01dc, 0x017d: 0x01e0, 0x017e: 0x01e4, 0x017f: 0x01e8,
+ // Block 0x6, offset 0x180
+ 0x0180: 0x01ec, 0x0183: 0x01f0, 0x0184: 0x01f4, 0x0185: 0x01f8,
+ 0x0186: 0x01fc, 0x0187: 0x0200, 0x0188: 0x0204, 0x0189: 0x0208,
+ 0x018c: 0x020c, 0x018d: 0x0210, 0x018e: 0x0214, 0x018f: 0x0218, 0x0190: 0x021c, 0x0191: 0x0220,
+ 0x0194: 0x0224, 0x0195: 0x0228, 0x0196: 0x022c, 0x0197: 0x0230,
+ 0x0198: 0x0234, 0x0199: 0x0238, 0x019a: 0x023c, 0x019b: 0x0240, 0x019c: 0x0244, 0x019d: 0x0248,
+ 0x019e: 0x024c, 0x019f: 0x0250, 0x01a0: 0x0254, 0x01a1: 0x0258, 0x01a2: 0x025c, 0x01a3: 0x0260,
+ 0x01a4: 0x0264, 0x01a5: 0x0268, 0x01a8: 0x026c, 0x01a9: 0x0270,
+ 0x01aa: 0x0274, 0x01ab: 0x0278, 0x01ac: 0x027c, 0x01ad: 0x0280, 0x01ae: 0x0284, 0x01af: 0x0288,
+ 0x01b0: 0x028c, 0x01b1: 0x0290, 0x01b2: 0x0294, 0x01b3: 0x0298, 0x01b4: 0x029c, 0x01b5: 0x02a0,
+ 0x01b6: 0x02a4, 0x01b7: 0x02a8, 0x01b8: 0x02ac, 0x01b9: 0x02b0, 0x01ba: 0x02b4, 0x01bb: 0x02b8,
+ 0x01bc: 0x02bc, 0x01bd: 0x02c0, 0x01be: 0x02c4, 0x01bf: 0x02c8,
+ // Block 0x7, offset 0x1c0
+ 0x01e0: 0x02ca, 0x01e1: 0x02ce,
+ 0x01ef: 0x02d2,
+ 0x01f0: 0x02d6,
+ // Block 0x8, offset 0x200
+ 0x0204: 0x02da, 0x0205: 0x02df,
+ 0x0206: 0x02e4, 0x0207: 0x02e9, 0x0208: 0x02ec, 0x0209: 0x02ef, 0x020a: 0x02f2, 0x020b: 0x02f5,
+ 0x020c: 0x02f8, 0x020d: 0x02fb, 0x020e: 0x02ff, 0x020f: 0x0303, 0x0210: 0x0307, 0x0211: 0x030b,
+ 0x0212: 0x030f, 0x0213: 0x0313, 0x0214: 0x0317, 0x0215: 0x031b, 0x0216: 0x0321, 0x0217: 0x0327,
+ 0x0218: 0x032d, 0x0219: 0x0333, 0x021a: 0x0339, 0x021b: 0x033f, 0x021c: 0x0345,
+ 0x021e: 0x034b, 0x021f: 0x0351, 0x0220: 0x0357, 0x0221: 0x035d, 0x0222: 0x0363, 0x0223: 0x0368,
+ 0x0226: 0x036d, 0x0227: 0x0371, 0x0228: 0x0375, 0x0229: 0x0379,
+ 0x022a: 0x037d, 0x022b: 0x0381, 0x022c: 0x0385, 0x022d: 0x038b, 0x022e: 0x0391, 0x022f: 0x0396,
+ 0x0230: 0x039b, 0x0231: 0x039f, 0x0232: 0x03a2, 0x0233: 0x03a5, 0x0234: 0x03a8, 0x0235: 0x03ac,
+ 0x0238: 0x03b0, 0x0239: 0x03b4, 0x023a: 0x03b8, 0x023b: 0x03be,
+ 0x023c: 0x03c4, 0x023d: 0x03c9, 0x023e: 0x03ce, 0x023f: 0x03d3,
+ // Block 0x9, offset 0x240
+ 0x0240: 0x03d8, 0x0241: 0x03dc, 0x0242: 0x03e0, 0x0243: 0x03e4, 0x0244: 0x03e8, 0x0245: 0x03ec,
+ 0x0246: 0x03f0, 0x0247: 0x03f4, 0x0248: 0x03f8, 0x0249: 0x03fc, 0x024a: 0x0400, 0x024b: 0x0404,
+ 0x024c: 0x0408, 0x024d: 0x040c, 0x024e: 0x0410, 0x024f: 0x0414, 0x0250: 0x0418, 0x0251: 0x041c,
+ 0x0252: 0x0420, 0x0253: 0x0424, 0x0254: 0x0428, 0x0255: 0x042c, 0x0256: 0x0430, 0x0257: 0x0434,
+ 0x0258: 0x0438, 0x0259: 0x043c, 0x025a: 0x0440, 0x025b: 0x0444,
+ 0x025e: 0x0448, 0x025f: 0x044c,
+ 0x0266: 0x0450, 0x0267: 0x0454, 0x0268: 0x0458, 0x0269: 0x045c,
+ 0x026a: 0x0460, 0x026b: 0x0466, 0x026c: 0x046c, 0x026d: 0x0472, 0x026e: 0x0478, 0x026f: 0x047c,
+ 0x0270: 0x0480, 0x0271: 0x0486, 0x0272: 0x048c, 0x0273: 0x0490,
+ // Block 0xa, offset 0x280
+ 0x02b0: 0x0494, 0x02b1: 0x0496, 0x02b2: 0x0499, 0x02b3: 0x049b, 0x02b4: 0x049d, 0x02b5: 0x04a0,
+ 0x02b6: 0x04a3, 0x02b7: 0x04a6, 0x02b8: 0x04a8,
+ // Block 0xb, offset 0x2c0
+ 0x02d8: 0x04aa, 0x02d9: 0x04ae, 0x02da: 0x04b2, 0x02db: 0x04b6, 0x02dc: 0x04ba, 0x02dd: 0x04be,
+ 0x02e0: 0x04c2, 0x02e1: 0x04c5, 0x02e2: 0x02c8, 0x02e3: 0x04c7,
+ 0x02e4: 0x04c9,
+ // Block 0xc, offset 0x300
+ 0x0300: 0x04cc, 0x0301: 0x04cf, 0x0303: 0x04d2, 0x0304: 0x04d5,
+ 0x0334: 0x04da,
+ 0x033a: 0x04dd,
+ 0x033e: 0x04e1,
+ // Block 0xd, offset 0x340
+ 0x0344: 0x0011, 0x0345: 0x04e8,
+ 0x0346: 0x04ee, 0x0347: 0x04f3, 0x0348: 0x04f6, 0x0349: 0x04fb, 0x034a: 0x0500,
+ 0x034c: 0x0505, 0x034e: 0x050a, 0x034f: 0x050f, 0x0350: 0x0514,
+ 0x036a: 0x051b, 0x036b: 0x0520, 0x036c: 0x0525, 0x036d: 0x052a, 0x036e: 0x052f, 0x036f: 0x0534,
+ 0x0370: 0x0539,
+ // Block 0xe, offset 0x380
+ 0x038a: 0x0540, 0x038b: 0x0545,
+ 0x038c: 0x054a, 0x038d: 0x054f, 0x038e: 0x0554, 0x0390: 0x0559, 0x0391: 0x055c,
+ 0x0392: 0x055f, 0x0393: 0x050a, 0x0394: 0x0520, 0x0395: 0x056c, 0x0396: 0x056f,
+ 0x03b0: 0x0572, 0x03b1: 0x0575, 0x03b2: 0x0578, 0x03b4: 0x057b, 0x03b5: 0x057e,
+ 0x03b9: 0x0581,
+ // Block 0xf, offset 0x3c0
+ 0x03c0: 0x0584, 0x03c1: 0x0589, 0x03c3: 0x058e,
+ 0x03c7: 0x0593,
+ 0x03cc: 0x0598, 0x03cd: 0x059d, 0x03ce: 0x05a2,
+ 0x03d9: 0x05a7,
+ 0x03f9: 0x05ac,
+ // Block 0x10, offset 0x400
+ 0x0410: 0x05b1, 0x0411: 0x05b6,
+ 0x0413: 0x05bb, 0x0417: 0x05c0,
+ 0x041c: 0x05c5, 0x041d: 0x05ca,
+ 0x041e: 0x05cf,
+ 0x0436: 0x05d4, 0x0437: 0x05d9,
+ // Block 0x11, offset 0x440
+ 0x0441: 0x05de, 0x0442: 0x05e3,
+ 0x0450: 0x05e8, 0x0451: 0x05ed,
+ 0x0452: 0x05f2, 0x0453: 0x05f7, 0x0456: 0x05fc, 0x0457: 0x0601,
+ 0x045a: 0x0606, 0x045b: 0x060b, 0x045c: 0x0610, 0x045d: 0x0615,
+ 0x045e: 0x061a, 0x045f: 0x061f, 0x0462: 0x0624, 0x0463: 0x0629,
+ 0x0464: 0x062e, 0x0465: 0x0633, 0x0466: 0x0638, 0x0467: 0x063d,
+ 0x046a: 0x0642, 0x046b: 0x0647, 0x046c: 0x064c, 0x046d: 0x0651, 0x046e: 0x0656, 0x046f: 0x065b,
+ 0x0470: 0x0660, 0x0471: 0x0665, 0x0472: 0x066a, 0x0473: 0x066f, 0x0474: 0x0674, 0x0475: 0x0679,
+ 0x0478: 0x067e, 0x0479: 0x0683,
+ // Block 0x12, offset 0x480
+ 0x0487: 0x0688,
+ // Block 0x13, offset 0x4c0
+ 0x04e2: 0x068d, 0x04e3: 0x0692,
+ 0x04e4: 0x0697, 0x04e5: 0x069c, 0x04e6: 0x06a1,
+ // Block 0x14, offset 0x500
+ 0x0535: 0x06a6,
+ 0x0536: 0x06ab, 0x0537: 0x06b0, 0x0538: 0x06b5,
+ // Block 0x15, offset 0x540
+ 0x0540: 0x06ba, 0x0542: 0x06bf,
+ 0x0553: 0x06c4,
+ // Block 0x16, offset 0x580
+ 0x05a9: 0x06c9,
+ 0x05b1: 0x06d0, 0x05b4: 0x06d7,
+ // Block 0x17, offset 0x5c0
+ 0x05d8: 0x06de, 0x05d9: 0x06e5, 0x05da: 0x06ec, 0x05db: 0x06f3, 0x05dc: 0x06fa, 0x05dd: 0x0701,
+ 0x05de: 0x0708, 0x05df: 0x070f,
+ // Block 0x18, offset 0x600
+ 0x060b: 0x0716,
+ 0x060c: 0x071d,
+ 0x061c: 0x0724, 0x061d: 0x072b,
+ 0x061f: 0x0732,
+ // Block 0x19, offset 0x640
+ 0x0673: 0x0739,
+ 0x0676: 0x0740,
+ // Block 0x1a, offset 0x680
+ 0x0699: 0x0747, 0x069a: 0x074e, 0x069b: 0x0755,
+ 0x069e: 0x075c,
+ // Block 0x1b, offset 0x6c0
+ 0x06c8: 0x0763, 0x06cb: 0x076a,
+ 0x06cc: 0x0771,
+ 0x06dc: 0x0778, 0x06dd: 0x077f,
+ // Block 0x1c, offset 0x700
+ 0x0714: 0x0786,
+ // Block 0x1d, offset 0x740
+ 0x074a: 0x078d, 0x074b: 0x0794,
+ 0x074c: 0x079b,
+ // Block 0x1e, offset 0x780
+ 0x0788: 0x07a2,
+ // Block 0x1f, offset 0x7c0
+ 0x07c0: 0x07a9,
+ 0x07c7: 0x07b0, 0x07c8: 0x07b7, 0x07ca: 0x07be, 0x07cb: 0x07c5,
+ // Block 0x20, offset 0x800
+ 0x080a: 0x07cf, 0x080b: 0x07d6,
+ 0x080c: 0x07dd,
+ // Block 0x21, offset 0x840
+ 0x085a: 0x07e4, 0x085c: 0x07eb, 0x085d: 0x07f2,
+ 0x085e: 0x07fc,
+ // Block 0x22, offset 0x880
+ 0x08b3: 0x0803,
+ // Block 0x23, offset 0x8c0
+ 0x08f3: 0x080a,
+ // Block 0x24, offset 0x900
+ 0x091c: 0x0811, 0x091d: 0x0818,
+ // Block 0x25, offset 0x940
+ 0x094c: 0x081f,
+ // Block 0x26, offset 0x980
+ 0x0983: 0x0823,
+ 0x098d: 0x082a,
+ 0x0992: 0x0831, 0x0997: 0x0838,
+ 0x099c: 0x083f,
+ 0x09a9: 0x0846,
+ 0x09b3: 0x084d, 0x09b5: 0x0854,
+ 0x09b6: 0x085b, 0x09b7: 0x0862, 0x09b8: 0x086c, 0x09b9: 0x0873,
+ // Block 0x27, offset 0x9c0
+ 0x09c1: 0x087d,
+ 0x09d3: 0x0884,
+ 0x09dd: 0x088b,
+ 0x09e2: 0x0892,
+ 0x09e7: 0x0899,
+ 0x09ec: 0x08a0,
+ 0x09f9: 0x08a7,
+ // Block 0x28, offset 0xa00
+ 0x0a26: 0x08ae,
+ // Block 0x29, offset 0xa40
+ 0x0a7c: 0x08b5,
+ // Block 0x2a, offset 0xa80
+ 0x0a86: 0x08b9, 0x0a88: 0x08c0, 0x0a8a: 0x08c7,
+ 0x0a8c: 0x08ce, 0x0a8e: 0x08d5,
+ 0x0a92: 0x08dc,
+ 0x0abb: 0x08e3,
+ 0x0abd: 0x08ea,
+ // Block 0x2b, offset 0xac0
+ 0x0ac0: 0x08f1, 0x0ac1: 0x08f8, 0x0ac3: 0x08ff,
+ // Block 0x2c, offset 0xb00
+ 0x0b2c: 0x0906, 0x0b2d: 0x0908, 0x0b2e: 0x090b,
+ 0x0b30: 0x090d, 0x0b31: 0x090f, 0x0b32: 0x0911, 0x0b33: 0x0914, 0x0b34: 0x0916, 0x0b35: 0x0918,
+ 0x0b36: 0x091a, 0x0b37: 0x091c, 0x0b38: 0x091e, 0x0b39: 0x0920, 0x0b3a: 0x0922,
+ 0x0b3c: 0x0924, 0x0b3d: 0x0926, 0x0b3e: 0x0929, 0x0b3f: 0x092b,
+ // Block 0x2d, offset 0xb40
+ 0x0b40: 0x092d, 0x0b41: 0x092f, 0x0b42: 0x0931, 0x0b43: 0x0007, 0x0b44: 0x0933, 0x0b45: 0x0936,
+ 0x0b46: 0x0939, 0x0b47: 0x093d, 0x0b48: 0x093f, 0x0b49: 0x0941, 0x0b4a: 0x0943, 0x0b4b: 0x0946,
+ 0x0b4c: 0x0949, 0x0b4d: 0x094c, 0x0b4f: 0x094e, 0x0b50: 0x0950, 0x0b51: 0x0952,
+ 0x0b52: 0x001e, 0x0b53: 0x0955, 0x0b54: 0x0958, 0x0b55: 0x095c, 0x0b56: 0x0960, 0x0b57: 0x0962,
+ 0x0b58: 0x0964, 0x0b59: 0x0966, 0x0b5a: 0x096a, 0x0b5b: 0x096d, 0x0b5c: 0x096f, 0x0b5d: 0x0559,
+ 0x0b5e: 0x0973, 0x0b5f: 0x0976, 0x0b60: 0x056c, 0x0b61: 0x0979, 0x0b62: 0x097c, 0x0b63: 0x049b,
+ 0x0b64: 0x0964, 0x0b65: 0x096d, 0x0b66: 0x0559, 0x0b67: 0x0973, 0x0b68: 0x0575, 0x0b69: 0x056c,
+ 0x0b6a: 0x0979,
+ 0x0b78: 0x097e,
+ // Block 0x2e, offset 0xb80
+ 0x0b9b: 0x0981, 0x0b9c: 0x0984, 0x0b9d: 0x0986,
+ 0x0b9e: 0x0989, 0x0b9f: 0x0949, 0x0ba0: 0x098c, 0x0ba1: 0x098e, 0x0ba2: 0x0991, 0x0ba3: 0x0994,
+ 0x0ba4: 0x0997, 0x0ba5: 0x099a, 0x0ba6: 0x099d, 0x0ba7: 0x09a0, 0x0ba8: 0x09a4, 0x0ba9: 0x09a7,
+ 0x0baa: 0x09aa, 0x0bab: 0x09ae, 0x0bac: 0x09b1, 0x0bad: 0x09b4, 0x0bae: 0x09b7, 0x0baf: 0x09ba,
+ 0x0bb0: 0x09bd, 0x0bb1: 0x09c0, 0x0bb2: 0x09c3, 0x0bb3: 0x09c6, 0x0bb4: 0x09c9, 0x0bb5: 0x09cc,
+ 0x0bb6: 0x09cf, 0x0bb7: 0x09d2, 0x0bb8: 0x09d5, 0x0bb9: 0x09d9, 0x0bba: 0x09dc, 0x0bbb: 0x09df,
+ 0x0bbc: 0x09e1, 0x0bbd: 0x09e4, 0x0bbe: 0x09e7, 0x0bbf: 0x055c,
+ // Block 0x2f, offset 0xbc0
+ 0x0bc0: 0x09ea, 0x0bc1: 0x09ee, 0x0bc2: 0x09f2, 0x0bc3: 0x09f6, 0x0bc4: 0x09fa, 0x0bc5: 0x09fe,
+ 0x0bc6: 0x0a02, 0x0bc7: 0x0a06, 0x0bc8: 0x0a0a, 0x0bc9: 0x0a10, 0x0bca: 0x0a16, 0x0bcb: 0x0a1a,
+ 0x0bcc: 0x0a1e, 0x0bcd: 0x0a22, 0x0bce: 0x0a26, 0x0bcf: 0x0a2a, 0x0bd0: 0x0a2e, 0x0bd1: 0x0a32,
+ 0x0bd2: 0x0a36, 0x0bd3: 0x0a3a, 0x0bd4: 0x0a3e, 0x0bd5: 0x0a44, 0x0bd6: 0x0a4a, 0x0bd7: 0x0a50,
+ 0x0bd8: 0x0a56, 0x0bd9: 0x0a5a, 0x0bda: 0x0a5e, 0x0bdb: 0x0a62, 0x0bdc: 0x0a66, 0x0bdd: 0x0a6c,
+ 0x0bde: 0x0a72, 0x0bdf: 0x0a76, 0x0be0: 0x0a7a, 0x0be1: 0x0a7e, 0x0be2: 0x0a82, 0x0be3: 0x0a86,
+ 0x0be4: 0x0a8a, 0x0be5: 0x0a8e, 0x0be6: 0x0a92, 0x0be7: 0x0a96, 0x0be8: 0x0a9a, 0x0be9: 0x0a9e,
+ 0x0bea: 0x0aa2, 0x0beb: 0x0aa6, 0x0bec: 0x0aaa, 0x0bed: 0x0aae, 0x0bee: 0x0ab2, 0x0bef: 0x0ab8,
+ 0x0bf0: 0x0abe, 0x0bf1: 0x0ac2, 0x0bf2: 0x0ac6, 0x0bf3: 0x0aca, 0x0bf4: 0x0ace, 0x0bf5: 0x0ad2,
+ 0x0bf6: 0x0ad6, 0x0bf7: 0x0ada, 0x0bf8: 0x0ade, 0x0bf9: 0x0ae4, 0x0bfa: 0x0aea, 0x0bfb: 0x0aee,
+ 0x0bfc: 0x0af2, 0x0bfd: 0x0af6, 0x0bfe: 0x0afa, 0x0bff: 0x0afe,
+ // Block 0x30, offset 0xc00
+ 0x0c00: 0x0b02, 0x0c01: 0x0b06, 0x0c02: 0x0b0a, 0x0c03: 0x0b0e, 0x0c04: 0x0b12, 0x0c05: 0x0b16,
+ 0x0c06: 0x0b1a, 0x0c07: 0x0b1e, 0x0c08: 0x0b22, 0x0c09: 0x0b26, 0x0c0a: 0x0b2a, 0x0c0b: 0x0b2e,
+ 0x0c0c: 0x0b32, 0x0c0d: 0x0b38, 0x0c0e: 0x0b3e, 0x0c0f: 0x0b44, 0x0c10: 0x0b4a, 0x0c11: 0x0b50,
+ 0x0c12: 0x0b56, 0x0c13: 0x0b5c, 0x0c14: 0x0b62, 0x0c15: 0x0b66, 0x0c16: 0x0b6a, 0x0c17: 0x0b6e,
+ 0x0c18: 0x0b72, 0x0c19: 0x0b76, 0x0c1a: 0x0b7a, 0x0c1b: 0x0b7e, 0x0c1c: 0x0b82, 0x0c1d: 0x0b88,
+ 0x0c1e: 0x0b8e, 0x0c1f: 0x0b92, 0x0c20: 0x0b96, 0x0c21: 0x0b9a, 0x0c22: 0x0b9e, 0x0c23: 0x0ba2,
+ 0x0c24: 0x0ba6, 0x0c25: 0x0bac, 0x0c26: 0x0bb2, 0x0c27: 0x0bb8, 0x0c28: 0x0bbe, 0x0c29: 0x0bc4,
+ 0x0c2a: 0x0bca, 0x0c2b: 0x0bce, 0x0c2c: 0x0bd2, 0x0c2d: 0x0bd6, 0x0c2e: 0x0bda, 0x0c2f: 0x0bde,
+ 0x0c30: 0x0be2, 0x0c31: 0x0be6, 0x0c32: 0x0bea, 0x0c33: 0x0bee, 0x0c34: 0x0bf2, 0x0c35: 0x0bf6,
+ 0x0c36: 0x0bfa, 0x0c37: 0x0bfe, 0x0c38: 0x0c02, 0x0c39: 0x0c08, 0x0c3a: 0x0c0e, 0x0c3b: 0x0c14,
+ 0x0c3c: 0x0c1a, 0x0c3d: 0x0c1e, 0x0c3e: 0x0c22, 0x0c3f: 0x0c26,
+ // Block 0x31, offset 0xc40
+ 0x0c40: 0x0c2a, 0x0c41: 0x0c2e, 0x0c42: 0x0c32, 0x0c43: 0x0c36, 0x0c44: 0x0c3a, 0x0c45: 0x0c3e,
+ 0x0c46: 0x0c42, 0x0c47: 0x0c46, 0x0c48: 0x0c4a, 0x0c49: 0x0c4e, 0x0c4a: 0x0c52, 0x0c4b: 0x0c56,
+ 0x0c4c: 0x0c5a, 0x0c4d: 0x0c5e, 0x0c4e: 0x0c62, 0x0c4f: 0x0c66, 0x0c50: 0x0c6a, 0x0c51: 0x0c6e,
+ 0x0c52: 0x0c72, 0x0c53: 0x0c76, 0x0c54: 0x0c7a, 0x0c55: 0x0c7e, 0x0c56: 0x0c82, 0x0c57: 0x0c86,
+ 0x0c58: 0x0c8a, 0x0c59: 0x0c8e, 0x0c5a: 0x0c92, 0x0c5b: 0x0b9a,
+ 0x0c60: 0x0c9b, 0x0c61: 0x0c9f, 0x0c62: 0x0ca3, 0x0c63: 0x0ca7,
+ 0x0c64: 0x0cab, 0x0c65: 0x0cb1, 0x0c66: 0x0cb7, 0x0c67: 0x0cbd, 0x0c68: 0x0cc3, 0x0c69: 0x0cc9,
+ 0x0c6a: 0x0ccf, 0x0c6b: 0x0cd5, 0x0c6c: 0x0cdb, 0x0c6d: 0x0ce1, 0x0c6e: 0x0ce7, 0x0c6f: 0x0ced,
+ 0x0c70: 0x0cf3, 0x0c71: 0x0cf9, 0x0c72: 0x0cff, 0x0c73: 0x0d05, 0x0c74: 0x0d0b, 0x0c75: 0x0d11,
+ 0x0c76: 0x0d17, 0x0c77: 0x0d1d, 0x0c78: 0x0d23, 0x0c79: 0x0d27, 0x0c7a: 0x0d2b, 0x0c7b: 0x0d2f,
+ 0x0c7c: 0x0d33, 0x0c7d: 0x0d37, 0x0c7e: 0x0d3b, 0x0c7f: 0x0d41,
+ // Block 0x32, offset 0xc80
+ 0x0c80: 0x0d47, 0x0c81: 0x0d4d, 0x0c82: 0x0d53, 0x0c83: 0x0d59, 0x0c84: 0x0d5f, 0x0c85: 0x0d65,
+ 0x0c86: 0x0d6b, 0x0c87: 0x0d71, 0x0c88: 0x0d77, 0x0c89: 0x0d7b, 0x0c8a: 0x0d7f, 0x0c8b: 0x0d83,
+ 0x0c8c: 0x0d87, 0x0c8d: 0x0d8b, 0x0c8e: 0x0d8f, 0x0c8f: 0x0d93, 0x0c90: 0x0d97, 0x0c91: 0x0d9d,
+ 0x0c92: 0x0da3, 0x0c93: 0x0da9, 0x0c94: 0x0daf, 0x0c95: 0x0db5, 0x0c96: 0x0dbb, 0x0c97: 0x0dc1,
+ 0x0c98: 0x0dc7, 0x0c99: 0x0dcd, 0x0c9a: 0x0dd3, 0x0c9b: 0x0dd9, 0x0c9c: 0x0ddf, 0x0c9d: 0x0de5,
+ 0x0c9e: 0x0deb, 0x0c9f: 0x0df1, 0x0ca0: 0x0df7, 0x0ca1: 0x0dfd, 0x0ca2: 0x0e03, 0x0ca3: 0x0e09,
+ 0x0ca4: 0x0e0f, 0x0ca5: 0x0e13, 0x0ca6: 0x0e17, 0x0ca7: 0x0e1b, 0x0ca8: 0x0e1f, 0x0ca9: 0x0e25,
+ 0x0caa: 0x0e2b, 0x0cab: 0x0e31, 0x0cac: 0x0e37, 0x0cad: 0x0e3d, 0x0cae: 0x0e43, 0x0caf: 0x0e49,
+ 0x0cb0: 0x0e4f, 0x0cb1: 0x0e55, 0x0cb2: 0x0e5b, 0x0cb3: 0x0e5f, 0x0cb4: 0x0e63, 0x0cb5: 0x0e67,
+ 0x0cb6: 0x0e6b, 0x0cb7: 0x0e6f, 0x0cb8: 0x0e73, 0x0cb9: 0x0e77,
+ // Block 0x33, offset 0xcc0
+ 0x0cc0: 0x0e7b, 0x0cc1: 0x0e80, 0x0cc2: 0x0e85, 0x0cc3: 0x0e8c, 0x0cc4: 0x0e93, 0x0cc5: 0x0e9a,
+ 0x0cc6: 0x0ea1, 0x0cc7: 0x0ea8, 0x0cc8: 0x0eaf, 0x0cc9: 0x0eb4, 0x0cca: 0x0eb9, 0x0ccb: 0x0ec0,
+ 0x0ccc: 0x0ec7, 0x0ccd: 0x0ece, 0x0cce: 0x0ed5, 0x0ccf: 0x0edc, 0x0cd0: 0x0ee3, 0x0cd1: 0x0ee8,
+ 0x0cd2: 0x0eed, 0x0cd3: 0x0ef4, 0x0cd4: 0x0efb, 0x0cd5: 0x0f02,
+ 0x0cd8: 0x0f09, 0x0cd9: 0x0f0e, 0x0cda: 0x0f13, 0x0cdb: 0x0f1a, 0x0cdc: 0x0f21, 0x0cdd: 0x0f28,
+ 0x0ce0: 0x0f2f, 0x0ce1: 0x0f34, 0x0ce2: 0x0f39, 0x0ce3: 0x0f40,
+ 0x0ce4: 0x0f47, 0x0ce5: 0x0f4e, 0x0ce6: 0x0f55, 0x0ce7: 0x0f5c, 0x0ce8: 0x0f63, 0x0ce9: 0x0f68,
+ 0x0cea: 0x0f6d, 0x0ceb: 0x0f74, 0x0cec: 0x0f7b, 0x0ced: 0x0f82, 0x0cee: 0x0f89, 0x0cef: 0x0f90,
+ 0x0cf0: 0x0f97, 0x0cf1: 0x0f9c, 0x0cf2: 0x0fa1, 0x0cf3: 0x0fa8, 0x0cf4: 0x0faf, 0x0cf5: 0x0fb6,
+ 0x0cf6: 0x0fbd, 0x0cf7: 0x0fc4, 0x0cf8: 0x0fcb, 0x0cf9: 0x0fd0, 0x0cfa: 0x0fd5, 0x0cfb: 0x0fdc,
+ 0x0cfc: 0x0fe3, 0x0cfd: 0x0fea, 0x0cfe: 0x0ff1, 0x0cff: 0x0ff8,
+ // Block 0x34, offset 0xd00
+ 0x0d00: 0x0fff, 0x0d01: 0x1004, 0x0d02: 0x1009, 0x0d03: 0x1010, 0x0d04: 0x1017, 0x0d05: 0x101e,
+ 0x0d08: 0x1025, 0x0d09: 0x102a, 0x0d0a: 0x102f, 0x0d0b: 0x1036,
+ 0x0d0c: 0x103d, 0x0d0d: 0x1044, 0x0d10: 0x104b, 0x0d11: 0x1050,
+ 0x0d12: 0x1055, 0x0d13: 0x105c, 0x0d14: 0x1063, 0x0d15: 0x106a, 0x0d16: 0x1071, 0x0d17: 0x1078,
+ 0x0d19: 0x107f, 0x0d1b: 0x1084, 0x0d1d: 0x108b,
+ 0x0d1f: 0x1092, 0x0d20: 0x1099, 0x0d21: 0x109e, 0x0d22: 0x10a3, 0x0d23: 0x10aa,
+ 0x0d24: 0x10b1, 0x0d25: 0x10b8, 0x0d26: 0x10bf, 0x0d27: 0x10c6, 0x0d28: 0x10cd, 0x0d29: 0x10d2,
+ 0x0d2a: 0x10d7, 0x0d2b: 0x10de, 0x0d2c: 0x10e5, 0x0d2d: 0x10ec, 0x0d2e: 0x10f3, 0x0d2f: 0x10fa,
+ 0x0d30: 0x1101, 0x0d31: 0x0525, 0x0d32: 0x1106, 0x0d33: 0x052a, 0x0d34: 0x110b, 0x0d35: 0x052f,
+ 0x0d36: 0x1110, 0x0d37: 0x0534, 0x0d38: 0x1115, 0x0d39: 0x054a, 0x0d3a: 0x111a, 0x0d3b: 0x054f,
+ 0x0d3c: 0x111f, 0x0d3d: 0x0554,
+ // Block 0x35, offset 0xd40
+ 0x0d40: 0x1124, 0x0d41: 0x112b, 0x0d42: 0x1132, 0x0d43: 0x113b, 0x0d44: 0x1144, 0x0d45: 0x114d,
+ 0x0d46: 0x1156, 0x0d47: 0x115f, 0x0d48: 0x1168, 0x0d49: 0x116f, 0x0d4a: 0x1176, 0x0d4b: 0x117f,
+ 0x0d4c: 0x1188, 0x0d4d: 0x1191, 0x0d4e: 0x119a, 0x0d4f: 0x11a3, 0x0d50: 0x11ac, 0x0d51: 0x11b3,
+ 0x0d52: 0x11ba, 0x0d53: 0x11c3, 0x0d54: 0x11cc, 0x0d55: 0x11d5, 0x0d56: 0x11de, 0x0d57: 0x11e7,
+ 0x0d58: 0x11f0, 0x0d59: 0x11f7, 0x0d5a: 0x11fe, 0x0d5b: 0x1207, 0x0d5c: 0x1210, 0x0d5d: 0x1219,
+ 0x0d5e: 0x1222, 0x0d5f: 0x122b, 0x0d60: 0x1234, 0x0d61: 0x123b, 0x0d62: 0x1242, 0x0d63: 0x124b,
+ 0x0d64: 0x1254, 0x0d65: 0x125d, 0x0d66: 0x1266, 0x0d67: 0x126f, 0x0d68: 0x1278, 0x0d69: 0x127f,
+ 0x0d6a: 0x1286, 0x0d6b: 0x128f, 0x0d6c: 0x1298, 0x0d6d: 0x12a1, 0x0d6e: 0x12aa, 0x0d6f: 0x12b3,
+ 0x0d70: 0x12bc, 0x0d71: 0x12c1, 0x0d72: 0x12c6, 0x0d73: 0x12cd, 0x0d74: 0x12d2,
+ 0x0d76: 0x12d9, 0x0d77: 0x12de, 0x0d78: 0x12e5, 0x0d79: 0x12ea, 0x0d7a: 0x12ef, 0x0d7b: 0x04ee,
+ 0x0d7c: 0x12f4, 0x0d7d: 0x12f9, 0x0d7e: 0x12fd, 0x0d7f: 0x12f9,
+ // Block 0x36, offset 0xd80
+ 0x0d80: 0x1300, 0x0d81: 0x1309, 0x0d82: 0x130f, 0x0d83: 0x1316, 0x0d84: 0x131b,
+ 0x0d86: 0x1322, 0x0d87: 0x1327, 0x0d88: 0x132e, 0x0d89: 0x04f6, 0x0d8a: 0x1333, 0x0d8b: 0x04fb,
+ 0x0d8c: 0x1338, 0x0d8d: 0x1343, 0x0d8e: 0x134f, 0x0d8f: 0x135b, 0x0d90: 0x1361, 0x0d91: 0x1366,
+ 0x0d92: 0x136b, 0x0d93: 0x0514, 0x0d96: 0x1372, 0x0d97: 0x1377,
+ 0x0d98: 0x137e, 0x0d99: 0x1383, 0x0d9a: 0x1388, 0x0d9b: 0x0500, 0x0d9d: 0x1393,
+ 0x0d9e: 0x139f, 0x0d9f: 0x13ab, 0x0da0: 0x13b1, 0x0da1: 0x13b6, 0x0da2: 0x13bb, 0x0da3: 0x0539,
+ 0x0da4: 0x13c2, 0x0da5: 0x13c7, 0x0da6: 0x13cc, 0x0da7: 0x13d1, 0x0da8: 0x13d8, 0x0da9: 0x13dd,
+ 0x0daa: 0x13e2, 0x0dab: 0x050a, 0x0dac: 0x13e7, 0x0dad: 0x13f1, 0x0dae: 0x04e8, 0x0daf: 0x13f7,
+ 0x0db2: 0x13f9, 0x0db3: 0x1400, 0x0db4: 0x1405,
+ 0x0db6: 0x140c, 0x0db7: 0x1411, 0x0db8: 0x1418, 0x0db9: 0x0505, 0x0dba: 0x141d, 0x0dbb: 0x050f,
+ 0x0dbc: 0x1422, 0x0dbd: 0x0011, 0x0dbe: 0x142a,
+ // Block 0x37, offset 0xdc0
+ 0x0dc0: 0x0001, 0x0dc1: 0x0001, 0x0dc2: 0x0001, 0x0dc3: 0x0001, 0x0dc4: 0x0001, 0x0dc5: 0x0001,
+ 0x0dc6: 0x0001, 0x0dc7: 0x0001, 0x0dc8: 0x0001, 0x0dc9: 0x0001, 0x0dca: 0x0001,
+ 0x0dd1: 0x1436,
+ 0x0dd7: 0x143a,
+ 0x0de4: 0x143e, 0x0de5: 0x1440, 0x0de6: 0x1443,
+ 0x0def: 0x0001,
+ 0x0df3: 0x1447, 0x0df4: 0x144e,
+ 0x0df6: 0x1458, 0x0df7: 0x145f,
+ 0x0dfc: 0x1469, 0x0dfe: 0x146c,
+ // Block 0x38, offset 0xe00
+ 0x0e07: 0x1470, 0x0e08: 0x1473, 0x0e09: 0x1476,
+ 0x0e17: 0x1479,
+ 0x0e1f: 0x0001,
+ 0x0e30: 0x1486, 0x0e31: 0x097c, 0x0e34: 0x1488, 0x0e35: 0x148a,
+ 0x0e36: 0x148c, 0x0e37: 0x148e, 0x0e38: 0x1490, 0x0e39: 0x1492, 0x0e3a: 0x1494, 0x0e3b: 0x1496,
+ 0x0e3c: 0x149a, 0x0e3d: 0x149c, 0x0e3e: 0x149e, 0x0e3f: 0x14a0,
+ // Block 0x39, offset 0xe40
+ 0x0e40: 0x1486, 0x0e41: 0x001c, 0x0e42: 0x000d, 0x0e43: 0x000f, 0x0e44: 0x1488, 0x0e45: 0x148a,
+ 0x0e46: 0x148c, 0x0e47: 0x148e, 0x0e48: 0x1490, 0x0e49: 0x1492, 0x0e4a: 0x1494, 0x0e4b: 0x1496,
+ 0x0e4c: 0x149a, 0x0e4d: 0x149c, 0x0e4e: 0x149e, 0x0e50: 0x0007, 0x0e51: 0x0941,
+ 0x0e52: 0x001e, 0x0e53: 0x04c7, 0x0e54: 0x0943, 0x0e55: 0x0494, 0x0e56: 0x094e, 0x0e57: 0x04c5,
+ 0x0e58: 0x0950, 0x0e59: 0x14a0, 0x0e5a: 0x0960, 0x0e5b: 0x02c8, 0x0e5c: 0x0962,
+ 0x0e68: 0x14a2,
+ // Block 0x3a, offset 0xe80
+ 0x0e80: 0x14a5, 0x0e81: 0x14a9, 0x0e82: 0x14ad, 0x0e83: 0x14af, 0x0e85: 0x14b3,
+ 0x0e86: 0x14b7, 0x0e87: 0x14bb, 0x0e89: 0x14be, 0x0e8a: 0x094c, 0x0e8b: 0x0916,
+ 0x0e8c: 0x0916, 0x0e8d: 0x0916, 0x0e8e: 0x0494, 0x0e8f: 0x14c2, 0x0e90: 0x0918, 0x0e91: 0x0918,
+ 0x0e92: 0x091e, 0x0e93: 0x04c5, 0x0e95: 0x0922, 0x0e96: 0x14c5,
+ 0x0e99: 0x0929, 0x0e9a: 0x14c8, 0x0e9b: 0x092b, 0x0e9c: 0x092b, 0x0e9d: 0x092b,
+ 0x0ea0: 0x14ca, 0x0ea1: 0x14cd, 0x0ea2: 0x14d1,
+ 0x0ea4: 0x14d4, 0x0ea6: 0x14d6, 0x0ea8: 0x14d4,
+ 0x0eaa: 0x091c, 0x0eab: 0x0046, 0x0eac: 0x090b, 0x0ead: 0x14ad, 0x0eaf: 0x0941,
+ 0x0eb0: 0x090f, 0x0eb1: 0x14d9, 0x0eb3: 0x0920, 0x0eb4: 0x001e, 0x0eb5: 0x14db,
+ 0x0eb6: 0x14de, 0x0eb7: 0x14e1, 0x0eb8: 0x14e4, 0x0eb9: 0x097c, 0x0ebb: 0x14e7,
+ 0x0ebc: 0x056f, 0x0ebd: 0x0973, 0x0ebe: 0x14eb, 0x0ebf: 0x14ee,
+ // Block 0x3b, offset 0xec0
+ 0x0ec0: 0x14f1, 0x0ec5: 0x090d,
+ 0x0ec6: 0x093f, 0x0ec7: 0x0941, 0x0ec8: 0x097c, 0x0ec9: 0x0499,
+ 0x0ed0: 0x14f5, 0x0ed1: 0x14fb,
+ 0x0ed2: 0x1501, 0x0ed3: 0x1508, 0x0ed4: 0x150e, 0x0ed5: 0x1514, 0x0ed6: 0x151a, 0x0ed7: 0x1520,
+ 0x0ed8: 0x1526, 0x0ed9: 0x152c, 0x0eda: 0x1532, 0x0edb: 0x1538, 0x0edc: 0x153e, 0x0edd: 0x1544,
+ 0x0ede: 0x154a, 0x0edf: 0x1550, 0x0ee0: 0x0918, 0x0ee1: 0x1555, 0x0ee2: 0x1558, 0x0ee3: 0x155c,
+ 0x0ee4: 0x155f, 0x0ee5: 0x1561, 0x0ee6: 0x1564, 0x0ee7: 0x1568, 0x0ee8: 0x156d, 0x0ee9: 0x1570,
+ 0x0eea: 0x1572, 0x0eeb: 0x1575, 0x0eec: 0x091e, 0x0eed: 0x14ad, 0x0eee: 0x090d, 0x0eef: 0x0920,
+ 0x0ef0: 0x097c, 0x0ef1: 0x1579, 0x0ef2: 0x157c, 0x0ef3: 0x1580, 0x0ef4: 0x096d, 0x0ef5: 0x1583,
+ 0x0ef6: 0x1586, 0x0ef7: 0x158a, 0x0ef8: 0x158f, 0x0ef9: 0x04c7, 0x0efa: 0x1592, 0x0efb: 0x1595,
+ 0x0efc: 0x04c5, 0x0efd: 0x0984, 0x0efe: 0x093f, 0x0eff: 0x0950,
+ // Block 0x3c, offset 0xf00
+ 0x0f09: 0x1599,
+ 0x0f1a: 0x159f, 0x0f1b: 0x15a5,
+ 0x0f2e: 0x15ab,
+ // Block 0x3d, offset 0xf40
+ 0x0f4d: 0x15b1, 0x0f4e: 0x15b7, 0x0f4f: 0x15bd,
+ // Block 0x3e, offset 0xf80
+ 0x0f84: 0x15c3,
+ 0x0f89: 0x15c9,
+ 0x0f8c: 0x15cf,
+ 0x0fa4: 0x15d5, 0x0fa6: 0x15db,
+ 0x0fac: 0x15e1, 0x0fad: 0x15e8, 0x0faf: 0x15f2,
+ 0x0fb0: 0x15f9,
+ // Block 0x3f, offset 0xfc0
+ 0x0fc1: 0x1603, 0x0fc4: 0x1609,
+ 0x0fc7: 0x160f, 0x0fc9: 0x1615,
+ 0x0fe0: 0x161b, 0x0fe2: 0x161f,
+ 0x0fed: 0x1625, 0x0fee: 0x162b, 0x0fef: 0x162f,
+ 0x0ff0: 0x1633, 0x0ff1: 0x1639, 0x0ff4: 0x163f, 0x0ff5: 0x1645,
+ 0x0ff8: 0x164b, 0x0ff9: 0x1651,
+ // Block 0x40, offset 0x1000
+ 0x1000: 0x1657, 0x1001: 0x165d, 0x1004: 0x1663, 0x1005: 0x1669,
+ 0x1008: 0x166f, 0x1009: 0x1675,
+ 0x102c: 0x167b, 0x102d: 0x1681, 0x102e: 0x1687, 0x102f: 0x168d,
+ // Block 0x41, offset 0x1040
+ 0x1060: 0x1693, 0x1061: 0x1699, 0x1062: 0x169f, 0x1063: 0x16a5,
+ 0x106a: 0x16ab, 0x106b: 0x16b1, 0x106c: 0x16b7, 0x106d: 0x16bd,
+ // Block 0x42, offset 0x1080
+ 0x10a9: 0x16c3,
+ 0x10aa: 0x16c7,
+ // Block 0x43, offset 0x10c0
+ 0x10e0: 0x001c, 0x10e1: 0x000d, 0x10e2: 0x000f, 0x10e3: 0x1488,
+ 0x10e4: 0x148a, 0x10e5: 0x148c, 0x10e6: 0x148e, 0x10e7: 0x1490, 0x10e8: 0x1492, 0x10e9: 0x16cb,
+ 0x10ea: 0x16ce, 0x10eb: 0x16d1, 0x10ec: 0x16d4, 0x10ed: 0x16d7, 0x10ee: 0x16da, 0x10ef: 0x16dd,
+ 0x10f0: 0x16e0, 0x10f1: 0x16e3, 0x10f2: 0x16e6, 0x10f3: 0x16e9, 0x10f4: 0x16ec, 0x10f5: 0x16f0,
+ 0x10f6: 0x16f4, 0x10f7: 0x16f8, 0x10f8: 0x16fc, 0x10f9: 0x1700, 0x10fa: 0x1704, 0x10fb: 0x1708,
+ 0x10fc: 0x170c, 0x10fd: 0x1710, 0x10fe: 0x1715, 0x10ff: 0x171a,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x171f, 0x1101: 0x1724, 0x1102: 0x1729, 0x1103: 0x172e, 0x1104: 0x1733, 0x1105: 0x1738,
+ 0x1106: 0x173d, 0x1107: 0x1742, 0x1108: 0x1747, 0x1109: 0x174a, 0x110a: 0x174d, 0x110b: 0x1750,
+ 0x110c: 0x1753, 0x110d: 0x1756, 0x110e: 0x1759, 0x110f: 0x175c, 0x1110: 0x175f, 0x1111: 0x1762,
+ 0x1112: 0x1766, 0x1113: 0x176a, 0x1114: 0x176e, 0x1115: 0x1772, 0x1116: 0x1776, 0x1117: 0x177a,
+ 0x1118: 0x177e, 0x1119: 0x1782, 0x111a: 0x1786, 0x111b: 0x178a, 0x111c: 0x178e, 0x111d: 0x1792,
+ 0x111e: 0x1796, 0x111f: 0x179a, 0x1120: 0x179e, 0x1121: 0x17a2, 0x1122: 0x17a6, 0x1123: 0x17aa,
+ 0x1124: 0x17ae, 0x1125: 0x17b2, 0x1126: 0x17b6, 0x1127: 0x17ba, 0x1128: 0x17be, 0x1129: 0x17c2,
+ 0x112a: 0x17c6, 0x112b: 0x17ca, 0x112c: 0x17ce, 0x112d: 0x17d2, 0x112e: 0x17d6, 0x112f: 0x17da,
+ 0x1130: 0x17de, 0x1131: 0x17e2, 0x1132: 0x17e6, 0x1133: 0x17ea, 0x1134: 0x17ee, 0x1135: 0x17f2,
+ 0x1136: 0x0906, 0x1137: 0x090b, 0x1138: 0x14ad, 0x1139: 0x090d, 0x113a: 0x090f, 0x113b: 0x14d9,
+ 0x113c: 0x0914, 0x113d: 0x0916, 0x113e: 0x0918, 0x113f: 0x091a,
+ // Block 0x45, offset 0x1140
+ 0x1140: 0x091c, 0x1141: 0x091e, 0x1142: 0x0920, 0x1143: 0x0922, 0x1144: 0x0924, 0x1145: 0x0929,
+ 0x1146: 0x14c8, 0x1147: 0x092b, 0x1148: 0x17f6, 0x1149: 0x092d, 0x114a: 0x092f, 0x114b: 0x155f,
+ 0x114c: 0x0931, 0x114d: 0x1570, 0x114e: 0x17f8, 0x114f: 0x14d4, 0x1150: 0x0007, 0x1151: 0x093d,
+ 0x1152: 0x0984, 0x1153: 0x093f, 0x1154: 0x0941, 0x1155: 0x098c, 0x1156: 0x094c, 0x1157: 0x0494,
+ 0x1158: 0x097c, 0x1159: 0x0499, 0x115a: 0x094e, 0x115b: 0x04c5, 0x115c: 0x0950, 0x115d: 0x14a0,
+ 0x115e: 0x001e, 0x115f: 0x0960, 0x1160: 0x17fa, 0x1161: 0x049b, 0x1162: 0x02c8, 0x1163: 0x0962,
+ 0x1164: 0x0964, 0x1165: 0x096d, 0x1166: 0x04a6, 0x1167: 0x04c7, 0x1168: 0x04a8, 0x1169: 0x09df,
+ 0x116a: 0x1486,
+ // Block 0x46, offset 0x1180
+ 0x118c: 0x17fc,
+ // Block 0x47, offset 0x11c0
+ 0x11f4: 0x1809, 0x11f5: 0x180d,
+ 0x11f6: 0x1810,
+ // Block 0x48, offset 0x1200
+ 0x121c: 0x1814,
+ // Block 0x49, offset 0x1240
+ 0x127c: 0x0499, 0x127d: 0x155f,
+ // Block 0x4a, offset 0x1280
+ 0x12af: 0x181a,
+ // Block 0x4b, offset 0x12c0
+ 0x12df: 0x181e,
+ // Block 0x4c, offset 0x1300
+ 0x1333: 0x1822,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x1826, 0x1341: 0x182a, 0x1342: 0x182e, 0x1343: 0x1832, 0x1344: 0x1836, 0x1345: 0x183a,
+ 0x1346: 0x183e, 0x1347: 0x1842, 0x1348: 0x1846, 0x1349: 0x184a, 0x134a: 0x184e, 0x134b: 0x1852,
+ 0x134c: 0x1856, 0x134d: 0x185a, 0x134e: 0x185e, 0x134f: 0x1862, 0x1350: 0x1866, 0x1351: 0x186a,
+ 0x1352: 0x186e, 0x1353: 0x1872, 0x1354: 0x1876, 0x1355: 0x187a, 0x1356: 0x187e, 0x1357: 0x1882,
+ 0x1358: 0x1886, 0x1359: 0x188a, 0x135a: 0x188e, 0x135b: 0x1892, 0x135c: 0x1896, 0x135d: 0x189a,
+ 0x135e: 0x189e, 0x135f: 0x18a2, 0x1360: 0x18a6, 0x1361: 0x18aa, 0x1362: 0x18ae, 0x1363: 0x18b2,
+ 0x1364: 0x18b6, 0x1365: 0x18ba, 0x1366: 0x18be, 0x1367: 0x18c2, 0x1368: 0x18c6, 0x1369: 0x18ca,
+ 0x136a: 0x18ce, 0x136b: 0x18d2, 0x136c: 0x18d6, 0x136d: 0x18da, 0x136e: 0x18de, 0x136f: 0x18e2,
+ 0x1370: 0x18e6, 0x1371: 0x18ea, 0x1372: 0x18ee, 0x1373: 0x18f2, 0x1374: 0x18f6, 0x1375: 0x18fa,
+ 0x1376: 0x18fe, 0x1377: 0x1902, 0x1378: 0x1906, 0x1379: 0x190a, 0x137a: 0x190e, 0x137b: 0x1912,
+ 0x137c: 0x1916, 0x137d: 0x191a, 0x137e: 0x191e, 0x137f: 0x1922,
+ // Block 0x4e, offset 0x1380
+ 0x1380: 0x1926, 0x1381: 0x192a, 0x1382: 0x192e, 0x1383: 0x1932, 0x1384: 0x1936, 0x1385: 0x193a,
+ 0x1386: 0x193e, 0x1387: 0x1942, 0x1388: 0x1946, 0x1389: 0x194a, 0x138a: 0x194e, 0x138b: 0x1952,
+ 0x138c: 0x1956, 0x138d: 0x195a, 0x138e: 0x195e, 0x138f: 0x1962, 0x1390: 0x1966, 0x1391: 0x196a,
+ 0x1392: 0x196e, 0x1393: 0x1972, 0x1394: 0x1976, 0x1395: 0x197a, 0x1396: 0x197e, 0x1397: 0x1982,
+ 0x1398: 0x1986, 0x1399: 0x198a, 0x139a: 0x198e, 0x139b: 0x1992, 0x139c: 0x1996, 0x139d: 0x199a,
+ 0x139e: 0x199e, 0x139f: 0x19a2, 0x13a0: 0x19a6, 0x13a1: 0x19aa, 0x13a2: 0x19ae, 0x13a3: 0x19b2,
+ 0x13a4: 0x19b6, 0x13a5: 0x19ba, 0x13a6: 0x19be, 0x13a7: 0x19c2, 0x13a8: 0x19c6, 0x13a9: 0x19ca,
+ 0x13aa: 0x19ce, 0x13ab: 0x19d2, 0x13ac: 0x19d6, 0x13ad: 0x19da, 0x13ae: 0x19de, 0x13af: 0x19e2,
+ 0x13b0: 0x19e6, 0x13b1: 0x19ea, 0x13b2: 0x19ee, 0x13b3: 0x19f2, 0x13b4: 0x19f6, 0x13b5: 0x19fa,
+ 0x13b6: 0x19fe, 0x13b7: 0x1a02, 0x13b8: 0x1a06, 0x13b9: 0x1a0a, 0x13ba: 0x1a0e, 0x13bb: 0x1a12,
+ 0x13bc: 0x1a16, 0x13bd: 0x1a1a, 0x13be: 0x1a1e, 0x13bf: 0x1a22,
+ // Block 0x4f, offset 0x13c0
+ 0x13c0: 0x1a26, 0x13c1: 0x1a2a, 0x13c2: 0x1a2e, 0x13c3: 0x1a32, 0x13c4: 0x1a36, 0x13c5: 0x1a3a,
+ 0x13c6: 0x1a3e, 0x13c7: 0x1a42, 0x13c8: 0x1a46, 0x13c9: 0x1a4a, 0x13ca: 0x1a4e, 0x13cb: 0x1a52,
+ 0x13cc: 0x1a56, 0x13cd: 0x1a5a, 0x13ce: 0x1a5e, 0x13cf: 0x1a62, 0x13d0: 0x1a66, 0x13d1: 0x1a6a,
+ 0x13d2: 0x1a6e, 0x13d3: 0x1a72, 0x13d4: 0x1a76, 0x13d5: 0x1a7a, 0x13d6: 0x1a7e, 0x13d7: 0x1a82,
+ 0x13d8: 0x1a86, 0x13d9: 0x1a8a, 0x13da: 0x1a8e, 0x13db: 0x1a92, 0x13dc: 0x1a96, 0x13dd: 0x1a9a,
+ 0x13de: 0x1a9e, 0x13df: 0x1aa2, 0x13e0: 0x1aa6, 0x13e1: 0x1aaa, 0x13e2: 0x1aae, 0x13e3: 0x1ab2,
+ 0x13e4: 0x1ab6, 0x13e5: 0x1aba, 0x13e6: 0x1abe, 0x13e7: 0x1ac2, 0x13e8: 0x1ac6, 0x13e9: 0x1aca,
+ 0x13ea: 0x1ace, 0x13eb: 0x1ad2, 0x13ec: 0x1ad6, 0x13ed: 0x1ada, 0x13ee: 0x1ade, 0x13ef: 0x1ae2,
+ 0x13f0: 0x1ae6, 0x13f1: 0x1aea, 0x13f2: 0x1aee, 0x13f3: 0x1af2, 0x13f4: 0x1af6, 0x13f5: 0x1afa,
+ 0x13f6: 0x1afe, 0x13f7: 0x1b02, 0x13f8: 0x1b06, 0x13f9: 0x1b0a, 0x13fa: 0x1b0e, 0x13fb: 0x1b12,
+ 0x13fc: 0x1b16, 0x13fd: 0x1b1a, 0x13fe: 0x1b1e, 0x13ff: 0x1b22,
+ // Block 0x50, offset 0x1400
+ 0x1400: 0x1b26, 0x1401: 0x1b2a, 0x1402: 0x1b2e, 0x1403: 0x1b32, 0x1404: 0x1b36, 0x1405: 0x1b3a,
+ 0x1406: 0x1b3e, 0x1407: 0x1b42, 0x1408: 0x1b46, 0x1409: 0x1b4a, 0x140a: 0x1b4e, 0x140b: 0x1b52,
+ 0x140c: 0x1b56, 0x140d: 0x1b5a, 0x140e: 0x1b5e, 0x140f: 0x1b62, 0x1410: 0x1b66, 0x1411: 0x1b6a,
+ 0x1412: 0x1b6e, 0x1413: 0x1b72, 0x1414: 0x1b76, 0x1415: 0x1b7a,
+ // Block 0x51, offset 0x1440
+ 0x1440: 0x0001,
+ 0x1476: 0x1b7e, 0x1478: 0x1882, 0x1479: 0x1b82, 0x147a: 0x1b86,
+ // Block 0x52, offset 0x1480
+ 0x148c: 0x1b8a, 0x148e: 0x1b91, 0x1490: 0x1b98,
+ 0x1492: 0x1b9f, 0x1494: 0x1ba6, 0x1496: 0x1bad,
+ 0x1498: 0x1bb4, 0x149a: 0x1bbb, 0x149c: 0x1bc2,
+ 0x149e: 0x1bc9, 0x14a0: 0x1bd0, 0x14a2: 0x1bd7,
+ 0x14a5: 0x1bde, 0x14a7: 0x1be5, 0x14a9: 0x1bec,
+ 0x14b0: 0x1bf3, 0x14b1: 0x1bfa, 0x14b3: 0x1c01, 0x14b4: 0x1c08,
+ 0x14b6: 0x1c0f, 0x14b7: 0x1c16, 0x14b9: 0x1c1d, 0x14ba: 0x1c24,
+ 0x14bc: 0x1c2b, 0x14bd: 0x1c32,
+ // Block 0x53, offset 0x14c0
+ 0x14d4: 0x1c39,
+ 0x14db: 0x1c40, 0x14dc: 0x1c45,
+ 0x14de: 0x1c4a, 0x14df: 0x1c51,
+ 0x14ec: 0x1c58, 0x14ee: 0x1c5f,
+ 0x14f0: 0x1c66, 0x14f2: 0x1c6d, 0x14f4: 0x1c74,
+ 0x14f6: 0x1c7b, 0x14f8: 0x1c82, 0x14fa: 0x1c89,
+ 0x14fc: 0x1c90, 0x14fe: 0x1c97,
+ // Block 0x54, offset 0x1500
+ 0x1500: 0x1c9e, 0x1502: 0x1ca5, 0x1505: 0x1cac,
+ 0x1507: 0x1cb3, 0x1509: 0x1cba,
+ 0x1510: 0x1cc1, 0x1511: 0x1cc8,
+ 0x1513: 0x1ccf, 0x1514: 0x1cd6, 0x1516: 0x1cdd, 0x1517: 0x1ce4,
+ 0x1519: 0x1ceb, 0x151a: 0x1cf2, 0x151c: 0x1cf9, 0x151d: 0x1d00,
+ 0x1534: 0x1d07,
+ 0x1537: 0x1d0e, 0x1538: 0x1d15, 0x1539: 0x1d1c, 0x153a: 0x1d23,
+ 0x153e: 0x1d2a, 0x153f: 0x1d31,
+ // Block 0x55, offset 0x1540
+ 0x1571: 0x1d38, 0x1572: 0x1d3c, 0x1573: 0x1d40, 0x1574: 0x1d44, 0x1575: 0x1d48,
+ 0x1576: 0x1d4c, 0x1577: 0x1d50, 0x1578: 0x1d54, 0x1579: 0x1d58, 0x157a: 0x1d5c, 0x157b: 0x1d60,
+ 0x157c: 0x1d64, 0x157d: 0x1d68, 0x157e: 0x1d6c, 0x157f: 0x1d70,
+ // Block 0x56, offset 0x1580
+ 0x1580: 0x1d74, 0x1581: 0x1d78, 0x1582: 0x1d7c, 0x1583: 0x1d80, 0x1584: 0x1d84, 0x1585: 0x1d88,
+ 0x1586: 0x1d8c, 0x1587: 0x1d90, 0x1588: 0x1d94, 0x1589: 0x1d98, 0x158a: 0x1d9c, 0x158b: 0x1da0,
+ 0x158c: 0x1da4, 0x158d: 0x1da8, 0x158e: 0x1dac, 0x158f: 0x1db0, 0x1590: 0x1db4, 0x1591: 0x1db8,
+ 0x1592: 0x1dbc, 0x1593: 0x1dc0, 0x1594: 0x1dc4, 0x1595: 0x1dc8, 0x1596: 0x1dcc, 0x1597: 0x1dd0,
+ 0x1598: 0x1dd4, 0x1599: 0x1dd8, 0x159a: 0x1ddc, 0x159b: 0x1de0, 0x159c: 0x1de4, 0x159d: 0x1de8,
+ 0x159e: 0x1dec, 0x159f: 0x1df0, 0x15a0: 0x1df4, 0x15a1: 0x1df8, 0x15a2: 0x1dfc, 0x15a3: 0x1e00,
+ 0x15a4: 0x1e04, 0x15a5: 0x1e08, 0x15a6: 0x1e0c, 0x15a7: 0x1e10, 0x15a8: 0x1e14, 0x15a9: 0x1e18,
+ 0x15aa: 0x1e1c, 0x15ab: 0x1e20, 0x15ac: 0x1e24, 0x15ad: 0x1e28, 0x15ae: 0x1e2c, 0x15af: 0x1e30,
+ 0x15b0: 0x1e34, 0x15b1: 0x1e38, 0x15b2: 0x1e3c, 0x15b3: 0x1e40, 0x15b4: 0x1e44, 0x15b5: 0x1e48,
+ 0x15b6: 0x1e4c, 0x15b7: 0x1e50, 0x15b8: 0x1e54, 0x15b9: 0x1e58, 0x15ba: 0x1e5c, 0x15bb: 0x1e60,
+ 0x15bc: 0x1e64, 0x15bd: 0x1e68, 0x15be: 0x1e6c, 0x15bf: 0x1e70,
+ // Block 0x57, offset 0x15c0
+ 0x15c0: 0x1e74, 0x15c1: 0x1e78, 0x15c2: 0x1e7c, 0x15c3: 0x1e80, 0x15c4: 0x1e84, 0x15c5: 0x1e88,
+ 0x15c6: 0x1e8c, 0x15c7: 0x1e90, 0x15c8: 0x1e94, 0x15c9: 0x1e98, 0x15ca: 0x1e9c, 0x15cb: 0x1ea0,
+ 0x15cc: 0x1ea4, 0x15cd: 0x1ea8, 0x15ce: 0x1eac,
+ 0x15d2: 0x1826, 0x15d3: 0x183e, 0x15d4: 0x1eb0, 0x15d5: 0x1eb4, 0x15d6: 0x1eb8, 0x15d7: 0x1ebc,
+ 0x15d8: 0x1ec0, 0x15d9: 0x1ec4, 0x15da: 0x1836, 0x15db: 0x1ec8, 0x15dc: 0x1ecc, 0x15dd: 0x1ed0,
+ 0x15de: 0x1ed4, 0x15df: 0x1846,
+ // Block 0x58, offset 0x1600
+ 0x1600: 0x1ed8, 0x1601: 0x1ede, 0x1602: 0x1ee4, 0x1603: 0x1eea, 0x1604: 0x1ef0, 0x1605: 0x1ef6,
+ 0x1606: 0x1efc, 0x1607: 0x1f02, 0x1608: 0x1f08, 0x1609: 0x1f0e, 0x160a: 0x1f14, 0x160b: 0x1f1a,
+ 0x160c: 0x1f20, 0x160d: 0x1f26, 0x160e: 0x1f2c, 0x160f: 0x1f35, 0x1610: 0x1f3e, 0x1611: 0x1f47,
+ 0x1612: 0x1f50, 0x1613: 0x1f59, 0x1614: 0x1f62, 0x1615: 0x1f6b, 0x1616: 0x1f74, 0x1617: 0x1f7d,
+ 0x1618: 0x1f86, 0x1619: 0x1f8f, 0x161a: 0x1f98, 0x161b: 0x1fa1, 0x161c: 0x1faa, 0x161d: 0x1fb3,
+ 0x161e: 0x1fc5, 0x1620: 0x1fd4, 0x1621: 0x1fda, 0x1622: 0x1fe0, 0x1623: 0x1fe6,
+ 0x1624: 0x1fec, 0x1625: 0x1ff2, 0x1626: 0x1ff8, 0x1627: 0x1ffe, 0x1628: 0x2004, 0x1629: 0x200a,
+ 0x162a: 0x2010, 0x162b: 0x2016, 0x162c: 0x201c, 0x162d: 0x2022, 0x162e: 0x2028, 0x162f: 0x202e,
+ 0x1630: 0x2034, 0x1631: 0x203a, 0x1632: 0x2040, 0x1633: 0x2046, 0x1634: 0x204c, 0x1635: 0x2052,
+ 0x1636: 0x2058, 0x1637: 0x205e, 0x1638: 0x2064, 0x1639: 0x206a, 0x163a: 0x2070, 0x163b: 0x2076,
+ 0x163c: 0x207c, 0x163d: 0x2082, 0x163e: 0x2088, 0x163f: 0x208e,
+ // Block 0x59, offset 0x1640
+ 0x1640: 0x2094, 0x1641: 0x209a, 0x1642: 0x20a0, 0x1643: 0x20a6, 0x1644: 0x20ac, 0x1645: 0x20b0,
+ 0x1646: 0x192e, 0x1647: 0x20b4,
+ 0x1650: 0x20b8, 0x1651: 0x20bc,
+ 0x1652: 0x20bf, 0x1653: 0x20c2, 0x1654: 0x20c5, 0x1655: 0x20c8, 0x1656: 0x20cb, 0x1657: 0x20ce,
+ 0x1658: 0x20d1, 0x1659: 0x20d4, 0x165a: 0x20d7, 0x165b: 0x20da, 0x165c: 0x20dd, 0x165d: 0x20e0,
+ 0x165e: 0x20e3, 0x165f: 0x20e6, 0x1660: 0x1d38, 0x1661: 0x1d44, 0x1662: 0x1d50, 0x1663: 0x1d58,
+ 0x1664: 0x1d78, 0x1665: 0x1d7c, 0x1666: 0x1d88, 0x1667: 0x1d90, 0x1668: 0x1d94, 0x1669: 0x1d9c,
+ 0x166a: 0x1da0, 0x166b: 0x1da4, 0x166c: 0x1da8, 0x166d: 0x1dac, 0x166e: 0x20e9, 0x166f: 0x20f0,
+ 0x1670: 0x20f7, 0x1671: 0x20fe, 0x1672: 0x2105, 0x1673: 0x210c, 0x1674: 0x2113, 0x1675: 0x211a,
+ 0x1676: 0x2121, 0x1677: 0x2128, 0x1678: 0x212f, 0x1679: 0x2136, 0x167a: 0x213d, 0x167b: 0x2144,
+ 0x167c: 0x214b, 0x167d: 0x215b, 0x167e: 0x2168,
+ // Block 0x5a, offset 0x1680
+ 0x1680: 0x1826, 0x1681: 0x183e, 0x1682: 0x1eb0, 0x1683: 0x1eb4, 0x1684: 0x216f, 0x1685: 0x2173,
+ 0x1686: 0x2177, 0x1687: 0x1852, 0x1688: 0x217b, 0x1689: 0x1882, 0x168a: 0x194a, 0x168b: 0x197a,
+ 0x168c: 0x1976, 0x168d: 0x194e, 0x168e: 0x1abe, 0x168f: 0x18a2, 0x1690: 0x1942, 0x1691: 0x217f,
+ 0x1692: 0x2183, 0x1693: 0x2187, 0x1694: 0x218b, 0x1695: 0x218f, 0x1696: 0x2193, 0x1697: 0x2197,
+ 0x1698: 0x219b, 0x1699: 0x219f, 0x169a: 0x21a3, 0x169b: 0x18ba, 0x169c: 0x21a7, 0x169d: 0x21ab,
+ 0x169e: 0x21af, 0x169f: 0x21b3, 0x16a0: 0x21b7, 0x16a1: 0x21bb, 0x16a2: 0x21bf, 0x16a3: 0x21c3,
+ 0x16a4: 0x1eb8, 0x16a5: 0x1ebc, 0x16a6: 0x1ec0, 0x16a7: 0x21c7, 0x16a8: 0x21cb, 0x16a9: 0x21cf,
+ 0x16aa: 0x21d3, 0x16ab: 0x21d7, 0x16ac: 0x21db, 0x16ad: 0x21df, 0x16ae: 0x21e3, 0x16af: 0x21e7,
+ 0x16b0: 0x21eb, 0x16b1: 0x21ef, 0x16b2: 0x21f2, 0x16b3: 0x21f5, 0x16b4: 0x21f8, 0x16b5: 0x21fb,
+ 0x16b6: 0x21fe, 0x16b7: 0x2201, 0x16b8: 0x2204, 0x16b9: 0x2207, 0x16ba: 0x220a, 0x16bb: 0x220d,
+ 0x16bc: 0x2210, 0x16bd: 0x2213, 0x16be: 0x2216, 0x16bf: 0x2219,
+ // Block 0x5b, offset 0x16c0
+ 0x16c0: 0x221c, 0x16c1: 0x2221, 0x16c2: 0x2226, 0x16c3: 0x222b, 0x16c4: 0x2230, 0x16c5: 0x2235,
+ 0x16c6: 0x223a, 0x16c7: 0x223f, 0x16c8: 0x2244, 0x16c9: 0x2249, 0x16ca: 0x224f, 0x16cb: 0x2255,
+ 0x16cc: 0x225b, 0x16cd: 0x225e, 0x16ce: 0x2262, 0x16cf: 0x2265, 0x16d0: 0x2269, 0x16d1: 0x226d,
+ 0x16d2: 0x2271, 0x16d3: 0x2275, 0x16d4: 0x2279, 0x16d5: 0x227d, 0x16d6: 0x2281, 0x16d7: 0x2285,
+ 0x16d8: 0x2289, 0x16d9: 0x228d, 0x16da: 0x2291, 0x16db: 0x2295, 0x16dc: 0x2299, 0x16dd: 0x229d,
+ 0x16de: 0x22a1, 0x16df: 0x22a5, 0x16e0: 0x22a9, 0x16e1: 0x22ad, 0x16e2: 0x22b1, 0x16e3: 0x22b5,
+ 0x16e4: 0x22b9, 0x16e5: 0x22bd, 0x16e6: 0x22c1, 0x16e7: 0x22c5, 0x16e8: 0x22c9, 0x16e9: 0x22cd,
+ 0x16ea: 0x22d1, 0x16eb: 0x22d5, 0x16ec: 0x22d9, 0x16ed: 0x22dd, 0x16ee: 0x22e1, 0x16ef: 0x22e5,
+ 0x16f0: 0x22e9, 0x16f1: 0x22ed, 0x16f2: 0x22f1, 0x16f3: 0x22f5, 0x16f4: 0x22f9, 0x16f5: 0x22fd,
+ 0x16f6: 0x2301, 0x16f7: 0x2305, 0x16f8: 0x2309, 0x16f9: 0x230d, 0x16fa: 0x2311, 0x16fb: 0x2315,
+ 0x16fc: 0x2319, 0x16fd: 0x231d, 0x16fe: 0x2321,
+ // Block 0x5c, offset 0x1700
+ 0x1700: 0x2325, 0x1701: 0x2335, 0x1702: 0x2342, 0x1703: 0x2352, 0x1704: 0x235c, 0x1705: 0x236c,
+ 0x1706: 0x2376, 0x1707: 0x2380, 0x1708: 0x2393, 0x1709: 0x23a0, 0x170a: 0x23aa, 0x170b: 0x23b4,
+ 0x170c: 0x23be, 0x170d: 0x23cb, 0x170e: 0x23d8, 0x170f: 0x23e5, 0x1710: 0x23f2, 0x1711: 0x23ff,
+ 0x1712: 0x240c, 0x1713: 0x2419, 0x1714: 0x242c, 0x1715: 0x2433, 0x1716: 0x2446, 0x1717: 0x2459,
+ 0x1718: 0x2469, 0x1719: 0x2476, 0x171a: 0x2489, 0x171b: 0x249c, 0x171c: 0x24a9, 0x171d: 0x24b3,
+ 0x171e: 0x24bd, 0x171f: 0x24ca, 0x1720: 0x24d7, 0x1721: 0x24e7, 0x1722: 0x24f7, 0x1723: 0x2501,
+ 0x1724: 0x250b, 0x1725: 0x2518, 0x1726: 0x2522, 0x1727: 0x252c, 0x1728: 0x2533, 0x1729: 0x253a,
+ 0x172a: 0x2544, 0x172b: 0x254e, 0x172c: 0x2561, 0x172d: 0x256e, 0x172e: 0x257e, 0x172f: 0x2591,
+ 0x1730: 0x259e, 0x1731: 0x25a8, 0x1732: 0x25b2, 0x1733: 0x25c5, 0x1734: 0x25d2, 0x1735: 0x25e5,
+ 0x1736: 0x25ef, 0x1737: 0x25ff, 0x1738: 0x2609, 0x1739: 0x2616, 0x173a: 0x2620, 0x173b: 0x262d,
+ 0x173c: 0x263d, 0x173d: 0x264a, 0x173e: 0x265a, 0x173f: 0x2667,
+ // Block 0x5d, offset 0x1740
+ 0x1740: 0x266e, 0x1741: 0x267e, 0x1742: 0x2688, 0x1743: 0x2692, 0x1744: 0x269f, 0x1745: 0x26a9,
+ 0x1746: 0x26b3, 0x1747: 0x26bd, 0x1748: 0x26cd, 0x1749: 0x26da, 0x174a: 0x26e1, 0x174b: 0x26f4,
+ 0x174c: 0x26fe, 0x174d: 0x270e, 0x174e: 0x271b, 0x174f: 0x2728, 0x1750: 0x2732, 0x1751: 0x273c,
+ 0x1752: 0x2749, 0x1753: 0x2750, 0x1754: 0x275d, 0x1755: 0x276d, 0x1756: 0x2774, 0x1757: 0x2787,
+ 0x1758: 0x2791, 0x1759: 0x2796, 0x175a: 0x279b, 0x175b: 0x27a0, 0x175c: 0x27a5, 0x175d: 0x27aa,
+ 0x175e: 0x27af, 0x175f: 0x27b4, 0x1760: 0x27b9, 0x1761: 0x27be, 0x1762: 0x27c3, 0x1763: 0x27c9,
+ 0x1764: 0x27cf, 0x1765: 0x27d5, 0x1766: 0x27db, 0x1767: 0x27e1, 0x1768: 0x27e7, 0x1769: 0x27ed,
+ 0x176a: 0x27f3, 0x176b: 0x27f9, 0x176c: 0x27ff, 0x176d: 0x2805, 0x176e: 0x280b, 0x176f: 0x2811,
+ 0x1770: 0x2817, 0x1771: 0x281d, 0x1772: 0x2821, 0x1773: 0x2824, 0x1774: 0x2827, 0x1775: 0x282b,
+ 0x1776: 0x282e, 0x1777: 0x2831, 0x1778: 0x2834, 0x1779: 0x2838, 0x177a: 0x283c, 0x177b: 0x283f,
+ 0x177c: 0x2846, 0x177d: 0x284d, 0x177e: 0x2854, 0x177f: 0x285b,
+ // Block 0x5e, offset 0x1780
+ 0x1780: 0x2868, 0x1781: 0x286b, 0x1782: 0x286e, 0x1783: 0x2872, 0x1784: 0x2875, 0x1785: 0x2878,
+ 0x1786: 0x287b, 0x1787: 0x287e, 0x1788: 0x2881, 0x1789: 0x2885, 0x178a: 0x288a, 0x178b: 0x288d,
+ 0x178c: 0x2890, 0x178d: 0x2894, 0x178e: 0x2898, 0x178f: 0x289b, 0x1790: 0x289e, 0x1791: 0x28a1,
+ 0x1792: 0x28a5, 0x1793: 0x28a9, 0x1794: 0x28ad, 0x1795: 0x28b1, 0x1796: 0x28b5, 0x1797: 0x28b8,
+ 0x1798: 0x28bb, 0x1799: 0x28be, 0x179a: 0x28c1, 0x179b: 0x28c4, 0x179c: 0x28c8, 0x179d: 0x28cb,
+ 0x179e: 0x28ce, 0x179f: 0x28d1, 0x17a0: 0x28d5, 0x17a1: 0x28d9, 0x17a2: 0x28dc, 0x17a3: 0x28e0,
+ 0x17a4: 0x28e4, 0x17a5: 0x28e8, 0x17a6: 0x28eb, 0x17a7: 0x28ef, 0x17a8: 0x28f5, 0x17a9: 0x28fc,
+ 0x17aa: 0x28ff, 0x17ab: 0x2903, 0x17ac: 0x2907, 0x17ad: 0x290b, 0x17ae: 0x290f, 0x17af: 0x2917,
+ 0x17b0: 0x2920, 0x17b1: 0x2923, 0x17b2: 0x2926, 0x17b3: 0x292a, 0x17b4: 0x292d, 0x17b5: 0x2930,
+ 0x17b6: 0x2933, 0x17b7: 0x2937, 0x17b8: 0x293a, 0x17b9: 0x293d, 0x17ba: 0x2940, 0x17bb: 0x2943,
+ 0x17bc: 0x2946, 0x17bd: 0x294a, 0x17be: 0x294d, 0x17bf: 0x2950,
+ // Block 0x5f, offset 0x17c0
+ 0x17c0: 0x2953, 0x17c1: 0x2957, 0x17c2: 0x295b, 0x17c3: 0x2960, 0x17c4: 0x2963, 0x17c5: 0x2966,
+ 0x17c6: 0x2969, 0x17c7: 0x2970, 0x17c8: 0x2974, 0x17c9: 0x2977, 0x17ca: 0x297a, 0x17cb: 0x297d,
+ 0x17cc: 0x2980, 0x17cd: 0x2983, 0x17ce: 0x2986, 0x17cf: 0x2989, 0x17d0: 0x298c, 0x17d1: 0x298f,
+ 0x17d2: 0x2992, 0x17d3: 0x2996, 0x17d4: 0x2999, 0x17d5: 0x299c, 0x17d6: 0x29a0, 0x17d7: 0x29a4,
+ 0x17d8: 0x29a7, 0x17d9: 0x29ac, 0x17da: 0x29b0, 0x17db: 0x29b3, 0x17dc: 0x29b6, 0x17dd: 0x29b9,
+ 0x17de: 0x29bc, 0x17df: 0x29c2, 0x17e0: 0x29c8, 0x17e1: 0x29cd, 0x17e2: 0x29d2, 0x17e3: 0x29d7,
+ 0x17e4: 0x29dc, 0x17e5: 0x29e1, 0x17e6: 0x29e6, 0x17e7: 0x29eb, 0x17e8: 0x29f0, 0x17e9: 0x29f5,
+ 0x17ea: 0x29fb, 0x17eb: 0x2a01, 0x17ec: 0x2a07, 0x17ed: 0x2a0d, 0x17ee: 0x2a13, 0x17ef: 0x2a19,
+ 0x17f0: 0x2a1f, 0x17f1: 0x2a25, 0x17f2: 0x2a2b, 0x17f3: 0x2a31, 0x17f4: 0x2a37, 0x17f5: 0x2a3d,
+ 0x17f6: 0x2a43, 0x17f7: 0x2a49, 0x17f8: 0x2a4f, 0x17f9: 0x2a55, 0x17fa: 0x2a5b, 0x17fb: 0x2a61,
+ 0x17fc: 0x2a67, 0x17fd: 0x2a6d, 0x17fe: 0x2a73, 0x17ff: 0x2a79,
+ // Block 0x60, offset 0x1800
+ 0x1830: 0x2a7d,
+ // Block 0x61, offset 0x1840
+ 0x1840: 0x2a81, 0x1841: 0x2a85, 0x1842: 0x1a9e, 0x1843: 0x2a89, 0x1844: 0x2a8d, 0x1845: 0x2a91,
+ 0x1846: 0x2a95, 0x1847: 0x1b76, 0x1848: 0x1b76, 0x1849: 0x2a99, 0x184a: 0x1abe, 0x184b: 0x2a9d,
+ 0x184c: 0x2aa1, 0x184d: 0x2aa5, 0x184e: 0x2aa9, 0x184f: 0x2aad, 0x1850: 0x2ab1, 0x1851: 0x2ab5,
+ 0x1852: 0x2ab9, 0x1853: 0x2abd, 0x1854: 0x2ac1, 0x1855: 0x2ac5, 0x1856: 0x2ac9, 0x1857: 0x2acd,
+ 0x1858: 0x2ad1, 0x1859: 0x2ad5, 0x185a: 0x2ad9, 0x185b: 0x2add, 0x185c: 0x2ae1, 0x185d: 0x2ae5,
+ 0x185e: 0x2ae9, 0x185f: 0x2aed, 0x1860: 0x2af1, 0x1861: 0x2af5, 0x1862: 0x2af9, 0x1863: 0x2afd,
+ 0x1864: 0x2b01, 0x1865: 0x2b05, 0x1866: 0x2b09, 0x1867: 0x2b0d, 0x1868: 0x2b11, 0x1869: 0x2b15,
+ 0x186a: 0x2b19, 0x186b: 0x2b1d, 0x186c: 0x2b21, 0x186d: 0x2b25, 0x186e: 0x2b29, 0x186f: 0x2b2d,
+ 0x1870: 0x2b31, 0x1871: 0x2b35, 0x1872: 0x2b39, 0x1873: 0x2b3d, 0x1874: 0x1a16, 0x1875: 0x2b41,
+ 0x1876: 0x2b45, 0x1877: 0x2b49, 0x1878: 0x2b4d, 0x1879: 0x2b51, 0x187a: 0x2b55, 0x187b: 0x2b59,
+ 0x187c: 0x2b5d, 0x187d: 0x2b61, 0x187e: 0x2b65, 0x187f: 0x2b69,
+ // Block 0x62, offset 0x1880
+ 0x1880: 0x1b3a, 0x1881: 0x2b6d, 0x1882: 0x2b71, 0x1883: 0x2b75, 0x1884: 0x2b79, 0x1885: 0x2b7d,
+ 0x1886: 0x2b81, 0x1887: 0x2b85, 0x1888: 0x2b89, 0x1889: 0x2b8d, 0x188a: 0x2b91, 0x188b: 0x2b95,
+ 0x188c: 0x2b99, 0x188d: 0x2b9d, 0x188e: 0x2ba1, 0x188f: 0x2ba5, 0x1890: 0x2ba9, 0x1891: 0x2bad,
+ 0x1892: 0x2bb1, 0x1893: 0x2bb5, 0x1894: 0x2bb9, 0x1895: 0x2bbd, 0x1896: 0x2bc1, 0x1897: 0x2bc5,
+ 0x1898: 0x2bc9, 0x1899: 0x2bcd, 0x189a: 0x2bd1, 0x189b: 0x2bd5, 0x189c: 0x2ac1, 0x189d: 0x2bd9,
+ 0x189e: 0x2bdd, 0x189f: 0x2be1, 0x18a0: 0x2be5, 0x18a1: 0x2be9, 0x18a2: 0x2bed, 0x18a3: 0x2bf1,
+ 0x18a4: 0x2bf5, 0x18a5: 0x2bf9, 0x18a6: 0x2bfd, 0x18a7: 0x2c01, 0x18a8: 0x2c05, 0x18a9: 0x2c09,
+ 0x18aa: 0x2c0d, 0x18ab: 0x2c11, 0x18ac: 0x2c15, 0x18ad: 0x2c19, 0x18ae: 0x2c1d, 0x18af: 0x2c21,
+ 0x18b0: 0x2c25, 0x18b1: 0x1aa6, 0x18b2: 0x2c29, 0x18b3: 0x2c2d, 0x18b4: 0x2c31, 0x18b5: 0x2c35,
+ 0x18b6: 0x2c39, 0x18b7: 0x2c3d, 0x18b8: 0x2c41, 0x18b9: 0x2c45, 0x18ba: 0x2c49, 0x18bb: 0x2c4d,
+ 0x18bc: 0x2c51, 0x18bd: 0x2c55, 0x18be: 0x2c59, 0x18bf: 0x2c5d,
+ // Block 0x63, offset 0x18c0
+ 0x18c0: 0x2c61, 0x18c1: 0x18ba, 0x18c2: 0x2c65, 0x18c3: 0x2c69, 0x18c4: 0x2c6d, 0x18c5: 0x2c71,
+ 0x18c6: 0x2c75, 0x18c7: 0x2c79, 0x18c8: 0x2c7d, 0x18c9: 0x2c81, 0x18ca: 0x186e, 0x18cb: 0x2c85,
+ 0x18cc: 0x2c89, 0x18cd: 0x2c8d, 0x18ce: 0x2c91, 0x18cf: 0x2c95, 0x18d0: 0x2c99, 0x18d1: 0x2c9d,
+ 0x18d2: 0x2ca1, 0x18d3: 0x2ca5, 0x18d4: 0x2ca9, 0x18d5: 0x2cad, 0x18d6: 0x2cb1, 0x18d7: 0x2cb5,
+ 0x18d8: 0x2cb9, 0x18d9: 0x2cbd, 0x18da: 0x2cc1, 0x18db: 0x2cc5, 0x18dc: 0x2cc9, 0x18dd: 0x2ccd,
+ 0x18de: 0x2cd1, 0x18df: 0x2cd5, 0x18e0: 0x2cd9, 0x18e1: 0x2c21, 0x18e2: 0x2cdd, 0x18e3: 0x2ce1,
+ 0x18e4: 0x2ce5, 0x18e5: 0x2ce9, 0x18e6: 0x2ced, 0x18e7: 0x2cf1, 0x18e8: 0x2cf5, 0x18e9: 0x2cf9,
+ 0x18ea: 0x2be1, 0x18eb: 0x2cfd, 0x18ec: 0x2d01, 0x18ed: 0x2d05, 0x18ee: 0x2d09, 0x18ef: 0x2d0d,
+ 0x18f0: 0x2d11, 0x18f1: 0x2d15, 0x18f2: 0x2d19, 0x18f3: 0x2d1d, 0x18f4: 0x2d21, 0x18f5: 0x2d25,
+ 0x18f6: 0x2d29, 0x18f7: 0x2d2d, 0x18f8: 0x2d31, 0x18f9: 0x2d35, 0x18fa: 0x2d39, 0x18fb: 0x2d3d,
+ 0x18fc: 0x2d41, 0x18fd: 0x2d45, 0x18fe: 0x2d49, 0x18ff: 0x2ac1,
+ // Block 0x64, offset 0x1900
+ 0x1900: 0x2d4d, 0x1901: 0x2d51, 0x1902: 0x2d55, 0x1903: 0x2d59, 0x1904: 0x1b72, 0x1905: 0x2d5d,
+ 0x1906: 0x2d61, 0x1907: 0x2d65, 0x1908: 0x2d69, 0x1909: 0x2d6d, 0x190a: 0x2d71, 0x190b: 0x2d75,
+ 0x190c: 0x2d79, 0x190d: 0x2d7d, 0x190e: 0x2d81, 0x190f: 0x2d85, 0x1910: 0x2d89, 0x1911: 0x2173,
+ 0x1912: 0x2d8d, 0x1913: 0x2d91, 0x1914: 0x2d95, 0x1915: 0x2d99, 0x1916: 0x2d9d, 0x1917: 0x2da1,
+ 0x1918: 0x2da5, 0x1919: 0x2da9, 0x191a: 0x2dad, 0x191b: 0x2be9, 0x191c: 0x2db1, 0x191d: 0x2db5,
+ 0x191e: 0x2db9, 0x191f: 0x2dbd, 0x1920: 0x2dc1, 0x1921: 0x2dc5, 0x1922: 0x2dc9, 0x1923: 0x2dcd,
+ 0x1924: 0x2dd1, 0x1925: 0x2dd5, 0x1926: 0x2dd9, 0x1927: 0x2ddd, 0x1928: 0x2de1, 0x1929: 0x1aba,
+ 0x192a: 0x2de5, 0x192b: 0x2de9, 0x192c: 0x2ded, 0x192d: 0x2df1, 0x192e: 0x2df5, 0x192f: 0x2df9,
+ 0x1930: 0x2dfd, 0x1931: 0x2e01, 0x1932: 0x2e05, 0x1933: 0x2e09, 0x1934: 0x2e0d, 0x1935: 0x2e11,
+ 0x1936: 0x2e15, 0x1937: 0x19f6, 0x1938: 0x2e19, 0x1939: 0x2e1d, 0x193a: 0x2e21, 0x193b: 0x2e25,
+ 0x193c: 0x2e29, 0x193d: 0x2e2d, 0x193e: 0x2e31, 0x193f: 0x2e35,
+ // Block 0x65, offset 0x1940
+ 0x1940: 0x2e39, 0x1941: 0x2e3d, 0x1942: 0x2e41, 0x1943: 0x2e45, 0x1944: 0x2e49, 0x1945: 0x2e4d,
+ 0x1946: 0x2e51, 0x1947: 0x2e55, 0x1948: 0x1a62, 0x1949: 0x2e59, 0x194a: 0x1a6e, 0x194b: 0x2e5d,
+ 0x194c: 0x2e61, 0x194d: 0x2e65, 0x1950: 0x2e69,
+ 0x1952: 0x2e6d, 0x1955: 0x2e71, 0x1956: 0x2e75, 0x1957: 0x2e79,
+ 0x1958: 0x2e7d, 0x1959: 0x2e81, 0x195a: 0x2e85, 0x195b: 0x2e89, 0x195c: 0x2e8d, 0x195d: 0x2e91,
+ 0x195e: 0x1a12, 0x1960: 0x2e95, 0x1962: 0x2e99,
+ 0x1965: 0x2e9d, 0x1966: 0x2ea1,
+ 0x196a: 0x2ea5, 0x196b: 0x2ea9, 0x196c: 0x2ead, 0x196d: 0x2eb1,
+ 0x1970: 0x2eb5, 0x1971: 0x2eb9, 0x1972: 0x2ebd, 0x1973: 0x2ec1, 0x1974: 0x2ec5, 0x1975: 0x2ec9,
+ 0x1976: 0x2ecd, 0x1977: 0x2ed1, 0x1978: 0x2ed5, 0x1979: 0x2ed9, 0x197a: 0x2edd, 0x197b: 0x2ee1,
+ 0x197c: 0x18d6, 0x197d: 0x2ee5, 0x197e: 0x2ee9, 0x197f: 0x2eed,
+ // Block 0x66, offset 0x1980
+ 0x1980: 0x2ef1, 0x1981: 0x2ef5, 0x1982: 0x2ef9, 0x1983: 0x2efd, 0x1984: 0x2f01, 0x1985: 0x2f05,
+ 0x1986: 0x2f09, 0x1987: 0x2f0d, 0x1988: 0x2f11, 0x1989: 0x2f15, 0x198a: 0x2f19, 0x198b: 0x2f1d,
+ 0x198c: 0x2187, 0x198d: 0x2f21, 0x198e: 0x2f25, 0x198f: 0x2f29, 0x1990: 0x2f2d, 0x1991: 0x2197,
+ 0x1992: 0x2f31, 0x1993: 0x2f35, 0x1994: 0x2f39, 0x1995: 0x2f3d, 0x1996: 0x2f41, 0x1997: 0x2cb1,
+ 0x1998: 0x2f45, 0x1999: 0x2f49, 0x199a: 0x2f4d, 0x199b: 0x2f51, 0x199c: 0x2f55, 0x199d: 0x2f59,
+ 0x199e: 0x2f59, 0x199f: 0x2f5d, 0x19a0: 0x2f61, 0x19a1: 0x2f65, 0x19a2: 0x2f69, 0x19a3: 0x2f6d,
+ 0x19a4: 0x2f71, 0x19a5: 0x2f75, 0x19a6: 0x2f79, 0x19a7: 0x2e9d, 0x19a8: 0x2f7d, 0x19a9: 0x2f81,
+ 0x19aa: 0x2f85, 0x19ab: 0x2f89, 0x19ac: 0x2f8d, 0x19ad: 0x2f92,
+ 0x19b0: 0x2f96, 0x19b1: 0x2f9a, 0x19b2: 0x2f9e, 0x19b3: 0x2fa2, 0x19b4: 0x2fa6, 0x19b5: 0x2faa,
+ 0x19b6: 0x2fae, 0x19b7: 0x2fb2, 0x19b8: 0x2ecd, 0x19b9: 0x2fb6, 0x19ba: 0x2fba, 0x19bb: 0x2fbe,
+ 0x19bc: 0x2e69, 0x19bd: 0x2fc2, 0x19be: 0x2fc6, 0x19bf: 0x2fca,
+ // Block 0x67, offset 0x19c0
+ 0x19c0: 0x2fce, 0x19c1: 0x2fd2, 0x19c2: 0x2fd6, 0x19c3: 0x2fda, 0x19c4: 0x2fde, 0x19c5: 0x2fe2,
+ 0x19c6: 0x2fe6, 0x19c7: 0x2fea, 0x19c8: 0x2fee, 0x19c9: 0x2eed, 0x19ca: 0x2ff2, 0x19cb: 0x2ef1,
+ 0x19cc: 0x2ff6, 0x19cd: 0x2ffa, 0x19ce: 0x2ffe, 0x19cf: 0x3002, 0x19d0: 0x3006, 0x19d1: 0x2e6d,
+ 0x19d2: 0x2b15, 0x19d3: 0x300a, 0x19d4: 0x300e, 0x19d5: 0x195a, 0x19d6: 0x2c25, 0x19d7: 0x2d71,
+ 0x19d8: 0x3012, 0x19d9: 0x3016, 0x19da: 0x2f0d, 0x19db: 0x301a, 0x19dc: 0x2f11, 0x19dd: 0x301e,
+ 0x19de: 0x3022, 0x19df: 0x3026, 0x19e0: 0x2e75, 0x19e1: 0x302a, 0x19e2: 0x302e, 0x19e3: 0x3032,
+ 0x19e4: 0x3036, 0x19e5: 0x303a, 0x19e6: 0x2e79, 0x19e7: 0x303e, 0x19e8: 0x3042, 0x19e9: 0x3046,
+ 0x19ea: 0x304a, 0x19eb: 0x304e, 0x19ec: 0x3052, 0x19ed: 0x2f41, 0x19ee: 0x3056, 0x19ef: 0x305a,
+ 0x19f0: 0x2cb1, 0x19f1: 0x305e, 0x19f2: 0x2f51, 0x19f3: 0x3062, 0x19f4: 0x3066, 0x19f5: 0x306a,
+ 0x19f6: 0x306e, 0x19f7: 0x3072, 0x19f8: 0x2f65, 0x19f9: 0x3076, 0x19fa: 0x2e99, 0x19fb: 0x307a,
+ 0x19fc: 0x2f69, 0x19fd: 0x2bd9, 0x19fe: 0x307e, 0x19ff: 0x2f6d,
+ // Block 0x68, offset 0x1a00
+ 0x1a00: 0x3082, 0x1a01: 0x2f75, 0x1a02: 0x3086, 0x1a03: 0x308a, 0x1a04: 0x308e, 0x1a05: 0x3092,
+ 0x1a06: 0x3096, 0x1a07: 0x2f7d, 0x1a08: 0x2e8d, 0x1a09: 0x309a, 0x1a0a: 0x2f81, 0x1a0b: 0x309e,
+ 0x1a0c: 0x2f85, 0x1a0d: 0x30a2, 0x1a0e: 0x1b76, 0x1a0f: 0x30a6, 0x1a10: 0x30ab, 0x1a11: 0x30b0,
+ 0x1a12: 0x30b5, 0x1a13: 0x30b9, 0x1a14: 0x30bd, 0x1a15: 0x30c1, 0x1a16: 0x30c6, 0x1a17: 0x30cb,
+ 0x1a18: 0x30d0, 0x1a19: 0x30d4,
+ // Block 0x69, offset 0x1a40
+ 0x1a40: 0x30d8, 0x1a41: 0x30db, 0x1a42: 0x30de, 0x1a43: 0x30e1, 0x1a44: 0x30e5, 0x1a45: 0x30e9,
+ 0x1a46: 0x30e9,
+ 0x1a53: 0x30ec, 0x1a54: 0x30f1, 0x1a55: 0x30f6, 0x1a56: 0x30fb, 0x1a57: 0x3100,
+ 0x1a5d: 0x3105,
+ 0x1a5f: 0x310a, 0x1a60: 0x310f, 0x1a61: 0x14db, 0x1a62: 0x14e4, 0x1a63: 0x3112,
+ 0x1a64: 0x3115, 0x1a65: 0x3118, 0x1a66: 0x311b, 0x1a67: 0x311e, 0x1a68: 0x3121, 0x1a69: 0x1494,
+ 0x1a6a: 0x3124, 0x1a6b: 0x3129, 0x1a6c: 0x312e, 0x1a6d: 0x3135, 0x1a6e: 0x313c, 0x1a6f: 0x3141,
+ 0x1a70: 0x3146, 0x1a71: 0x314b, 0x1a72: 0x3150, 0x1a73: 0x3155, 0x1a74: 0x315a, 0x1a75: 0x315f,
+ 0x1a76: 0x3164, 0x1a78: 0x3169, 0x1a79: 0x316e, 0x1a7a: 0x3173, 0x1a7b: 0x3178,
+ 0x1a7c: 0x317d, 0x1a7e: 0x3182,
+ // Block 0x6a, offset 0x1a80
+ 0x1a80: 0x3187, 0x1a81: 0x318c, 0x1a83: 0x3191, 0x1a84: 0x3196,
+ 0x1a86: 0x319b, 0x1a87: 0x31a0, 0x1a88: 0x31a5, 0x1a89: 0x31aa, 0x1a8a: 0x31af, 0x1a8b: 0x31b4,
+ 0x1a8c: 0x31b9, 0x1a8d: 0x31be, 0x1a8e: 0x31c3, 0x1a8f: 0x31c8, 0x1a90: 0x31cd, 0x1a91: 0x31cd,
+ 0x1a92: 0x31d0, 0x1a93: 0x31d0, 0x1a94: 0x31d0, 0x1a95: 0x31d0, 0x1a96: 0x31d3, 0x1a97: 0x31d3,
+ 0x1a98: 0x31d3, 0x1a99: 0x31d3, 0x1a9a: 0x31d6, 0x1a9b: 0x31d6, 0x1a9c: 0x31d6, 0x1a9d: 0x31d6,
+ 0x1a9e: 0x31d9, 0x1a9f: 0x31d9, 0x1aa0: 0x31d9, 0x1aa1: 0x31d9, 0x1aa2: 0x31dc, 0x1aa3: 0x31dc,
+ 0x1aa4: 0x31dc, 0x1aa5: 0x31dc, 0x1aa6: 0x31df, 0x1aa7: 0x31df, 0x1aa8: 0x31df, 0x1aa9: 0x31df,
+ 0x1aaa: 0x31e2, 0x1aab: 0x31e2, 0x1aac: 0x31e2, 0x1aad: 0x31e2, 0x1aae: 0x31e5, 0x1aaf: 0x31e5,
+ 0x1ab0: 0x31e5, 0x1ab1: 0x31e5, 0x1ab2: 0x31e8, 0x1ab3: 0x31e8, 0x1ab4: 0x31e8, 0x1ab5: 0x31e8,
+ 0x1ab6: 0x31eb, 0x1ab7: 0x31eb, 0x1ab8: 0x31eb, 0x1ab9: 0x31eb, 0x1aba: 0x31ee, 0x1abb: 0x31ee,
+ 0x1abc: 0x31ee, 0x1abd: 0x31ee, 0x1abe: 0x31f1, 0x1abf: 0x31f1,
+ // Block 0x6b, offset 0x1ac0
+ 0x1ac0: 0x31f1, 0x1ac1: 0x31f1, 0x1ac2: 0x31f4, 0x1ac3: 0x31f4, 0x1ac4: 0x31f7, 0x1ac5: 0x31f7,
+ 0x1ac6: 0x31fa, 0x1ac7: 0x31fa, 0x1ac8: 0x31fd, 0x1ac9: 0x31fd, 0x1aca: 0x3200, 0x1acb: 0x3200,
+ 0x1acc: 0x3203, 0x1acd: 0x3203, 0x1ace: 0x3206, 0x1acf: 0x3206, 0x1ad0: 0x3206, 0x1ad1: 0x3206,
+ 0x1ad2: 0x3209, 0x1ad3: 0x3209, 0x1ad4: 0x3209, 0x1ad5: 0x3209, 0x1ad6: 0x320c, 0x1ad7: 0x320c,
+ 0x1ad8: 0x320c, 0x1ad9: 0x320c, 0x1ada: 0x320f, 0x1adb: 0x320f, 0x1adc: 0x320f, 0x1add: 0x320f,
+ 0x1ade: 0x3212, 0x1adf: 0x3212, 0x1ae0: 0x3215, 0x1ae1: 0x3215, 0x1ae2: 0x3215, 0x1ae3: 0x3215,
+ 0x1ae4: 0x06ba, 0x1ae5: 0x06ba, 0x1ae6: 0x3218, 0x1ae7: 0x3218, 0x1ae8: 0x3218, 0x1ae9: 0x3218,
+ 0x1aea: 0x321b, 0x1aeb: 0x321b, 0x1aec: 0x321b, 0x1aed: 0x321b, 0x1aee: 0x321e, 0x1aef: 0x321e,
+ 0x1af0: 0x06c4, 0x1af1: 0x06c4,
+ // Block 0x6c, offset 0x1b00
+ 0x1b13: 0x3221, 0x1b14: 0x3221, 0x1b15: 0x3221, 0x1b16: 0x3221, 0x1b17: 0x3224,
+ 0x1b18: 0x3224, 0x1b19: 0x3227, 0x1b1a: 0x3227, 0x1b1b: 0x322a, 0x1b1c: 0x322a, 0x1b1d: 0x06b0,
+ 0x1b1e: 0x322d, 0x1b1f: 0x322d, 0x1b20: 0x3230, 0x1b21: 0x3230, 0x1b22: 0x3233, 0x1b23: 0x3233,
+ 0x1b24: 0x3236, 0x1b25: 0x3236, 0x1b26: 0x3236, 0x1b27: 0x3236, 0x1b28: 0x3239, 0x1b29: 0x3239,
+ 0x1b2a: 0x323c, 0x1b2b: 0x323c, 0x1b2c: 0x3243, 0x1b2d: 0x3243, 0x1b2e: 0x324a, 0x1b2f: 0x324a,
+ 0x1b30: 0x3251, 0x1b31: 0x3251, 0x1b32: 0x3258, 0x1b33: 0x3258, 0x1b34: 0x325f, 0x1b35: 0x325f,
+ 0x1b36: 0x3266, 0x1b37: 0x3266, 0x1b38: 0x3266, 0x1b39: 0x326d, 0x1b3a: 0x326d, 0x1b3b: 0x326d,
+ 0x1b3c: 0x3274, 0x1b3d: 0x3274, 0x1b3e: 0x3274, 0x1b3f: 0x3274,
+ // Block 0x6d, offset 0x1b40
+ 0x1b40: 0x3277, 0x1b41: 0x327e, 0x1b42: 0x3285, 0x1b43: 0x326d, 0x1b44: 0x328c, 0x1b45: 0x3293,
+ 0x1b46: 0x3298, 0x1b47: 0x329d, 0x1b48: 0x32a2, 0x1b49: 0x32a7, 0x1b4a: 0x32ac, 0x1b4b: 0x32b1,
+ 0x1b4c: 0x32b6, 0x1b4d: 0x32bb, 0x1b4e: 0x32c0, 0x1b4f: 0x32c5, 0x1b50: 0x32ca, 0x1b51: 0x32cf,
+ 0x1b52: 0x32d4, 0x1b53: 0x32d9, 0x1b54: 0x32de, 0x1b55: 0x32e3, 0x1b56: 0x32e8, 0x1b57: 0x32ed,
+ 0x1b58: 0x32f2, 0x1b59: 0x32f7, 0x1b5a: 0x32fc, 0x1b5b: 0x3301, 0x1b5c: 0x3306, 0x1b5d: 0x330b,
+ 0x1b5e: 0x3310, 0x1b5f: 0x3315, 0x1b60: 0x331a, 0x1b61: 0x331f, 0x1b62: 0x3324, 0x1b63: 0x3329,
+ 0x1b64: 0x332e, 0x1b65: 0x3333, 0x1b66: 0x3338, 0x1b67: 0x333d, 0x1b68: 0x3342, 0x1b69: 0x3347,
+ 0x1b6a: 0x334c, 0x1b6b: 0x3351, 0x1b6c: 0x3356, 0x1b6d: 0x335b, 0x1b6e: 0x3360, 0x1b6f: 0x3365,
+ 0x1b70: 0x336a, 0x1b71: 0x336f, 0x1b72: 0x3374, 0x1b73: 0x3379, 0x1b74: 0x337e, 0x1b75: 0x3383,
+ 0x1b76: 0x3388, 0x1b77: 0x338d, 0x1b78: 0x3392, 0x1b79: 0x3397, 0x1b7a: 0x339c, 0x1b7b: 0x33a1,
+ 0x1b7c: 0x33a6, 0x1b7d: 0x33ab, 0x1b7e: 0x33b0, 0x1b7f: 0x33b5,
+ // Block 0x6e, offset 0x1b80
+ 0x1b80: 0x33ba, 0x1b81: 0x33bf, 0x1b82: 0x33c4, 0x1b83: 0x33c9, 0x1b84: 0x33ce, 0x1b85: 0x33d3,
+ 0x1b86: 0x33d8, 0x1b87: 0x33dd, 0x1b88: 0x33e2, 0x1b89: 0x33e7, 0x1b8a: 0x33ec, 0x1b8b: 0x33f1,
+ 0x1b8c: 0x33f6, 0x1b8d: 0x33fb, 0x1b8e: 0x3400, 0x1b8f: 0x3405, 0x1b90: 0x340a, 0x1b91: 0x340f,
+ 0x1b92: 0x3414, 0x1b93: 0x3419, 0x1b94: 0x341e, 0x1b95: 0x3423, 0x1b96: 0x3428, 0x1b97: 0x342d,
+ 0x1b98: 0x3432, 0x1b99: 0x3437, 0x1b9a: 0x343c, 0x1b9b: 0x3441, 0x1b9c: 0x3446, 0x1b9d: 0x344b,
+ 0x1b9e: 0x3450, 0x1b9f: 0x3456, 0x1ba0: 0x345c, 0x1ba1: 0x3462, 0x1ba2: 0x3468, 0x1ba3: 0x346e,
+ 0x1ba4: 0x3474, 0x1ba5: 0x347b, 0x1ba6: 0x3285, 0x1ba7: 0x3482, 0x1ba8: 0x326d, 0x1ba9: 0x328c,
+ 0x1baa: 0x3489, 0x1bab: 0x348e, 0x1bac: 0x32a2, 0x1bad: 0x3493, 0x1bae: 0x32a7, 0x1baf: 0x32ac,
+ 0x1bb0: 0x3498, 0x1bb1: 0x349d, 0x1bb2: 0x32c0, 0x1bb3: 0x34a2, 0x1bb4: 0x32c5, 0x1bb5: 0x32ca,
+ 0x1bb6: 0x34a7, 0x1bb7: 0x34ac, 0x1bb8: 0x32d4, 0x1bb9: 0x34b1, 0x1bba: 0x32d9, 0x1bbb: 0x32de,
+ 0x1bbc: 0x336f, 0x1bbd: 0x3374, 0x1bbe: 0x3383, 0x1bbf: 0x3388,
+ // Block 0x6f, offset 0x1bc0
+ 0x1bc0: 0x338d, 0x1bc1: 0x33a1, 0x1bc2: 0x33a6, 0x1bc3: 0x33ab, 0x1bc4: 0x33b0, 0x1bc5: 0x33c4,
+ 0x1bc6: 0x33c9, 0x1bc7: 0x33ce, 0x1bc8: 0x34b6, 0x1bc9: 0x33e2, 0x1bca: 0x34bb, 0x1bcb: 0x34c0,
+ 0x1bcc: 0x3400, 0x1bcd: 0x34c5, 0x1bce: 0x3405, 0x1bcf: 0x340a, 0x1bd0: 0x344b, 0x1bd1: 0x34ca,
+ 0x1bd2: 0x34cf, 0x1bd3: 0x3432, 0x1bd4: 0x34d4, 0x1bd5: 0x3437, 0x1bd6: 0x343c, 0x1bd7: 0x3277,
+ 0x1bd8: 0x327e, 0x1bd9: 0x34d9, 0x1bda: 0x3285, 0x1bdb: 0x34e0, 0x1bdc: 0x3293, 0x1bdd: 0x3298,
+ 0x1bde: 0x329d, 0x1bdf: 0x32a2, 0x1be0: 0x34e7, 0x1be1: 0x32b1, 0x1be2: 0x32b6, 0x1be3: 0x32bb,
+ 0x1be4: 0x32c0, 0x1be5: 0x34ec, 0x1be6: 0x32d4, 0x1be7: 0x32e3, 0x1be8: 0x32e8, 0x1be9: 0x32ed,
+ 0x1bea: 0x32f2, 0x1beb: 0x32f7, 0x1bec: 0x3301, 0x1bed: 0x3306, 0x1bee: 0x330b, 0x1bef: 0x3310,
+ 0x1bf0: 0x3315, 0x1bf1: 0x331a, 0x1bf2: 0x34f1, 0x1bf3: 0x331f, 0x1bf4: 0x3324, 0x1bf5: 0x3329,
+ 0x1bf6: 0x332e, 0x1bf7: 0x3333, 0x1bf8: 0x3338, 0x1bf9: 0x3342, 0x1bfa: 0x3347, 0x1bfb: 0x334c,
+ 0x1bfc: 0x3351, 0x1bfd: 0x3356, 0x1bfe: 0x335b, 0x1bff: 0x3360,
+ // Block 0x70, offset 0x1c00
+ 0x1c00: 0x3365, 0x1c01: 0x336a, 0x1c02: 0x3379, 0x1c03: 0x337e, 0x1c04: 0x3392, 0x1c05: 0x3397,
+ 0x1c06: 0x339c, 0x1c07: 0x33a1, 0x1c08: 0x33a6, 0x1c09: 0x33b5, 0x1c0a: 0x33ba, 0x1c0b: 0x33bf,
+ 0x1c0c: 0x33c4, 0x1c0d: 0x34f6, 0x1c0e: 0x33d3, 0x1c0f: 0x33d8, 0x1c10: 0x33dd, 0x1c11: 0x33e2,
+ 0x1c12: 0x33f1, 0x1c13: 0x33f6, 0x1c14: 0x33fb, 0x1c15: 0x3400, 0x1c16: 0x34fb, 0x1c17: 0x340f,
+ 0x1c18: 0x3414, 0x1c19: 0x3500, 0x1c1a: 0x3423, 0x1c1b: 0x3428, 0x1c1c: 0x342d, 0x1c1d: 0x3432,
+ 0x1c1e: 0x3505, 0x1c1f: 0x3285, 0x1c20: 0x34e0, 0x1c21: 0x32a2, 0x1c22: 0x34e7, 0x1c23: 0x32c0,
+ 0x1c24: 0x34ec, 0x1c25: 0x32d4, 0x1c26: 0x350a, 0x1c27: 0x3315, 0x1c28: 0x350f, 0x1c29: 0x3514,
+ 0x1c2a: 0x3519, 0x1c2b: 0x33a1, 0x1c2c: 0x33a6, 0x1c2d: 0x33c4, 0x1c2e: 0x3400, 0x1c2f: 0x34fb,
+ 0x1c30: 0x3432, 0x1c31: 0x3505, 0x1c32: 0x351e, 0x1c33: 0x3525, 0x1c34: 0x352c, 0x1c35: 0x3533,
+ 0x1c36: 0x3538, 0x1c37: 0x353d, 0x1c38: 0x3542, 0x1c39: 0x3547, 0x1c3a: 0x354c, 0x1c3b: 0x3551,
+ 0x1c3c: 0x3556, 0x1c3d: 0x355b, 0x1c3e: 0x3560, 0x1c3f: 0x3565,
+ // Block 0x71, offset 0x1c40
+ 0x1c40: 0x356a, 0x1c41: 0x356f, 0x1c42: 0x3574, 0x1c43: 0x3579, 0x1c44: 0x357e, 0x1c45: 0x3583,
+ 0x1c46: 0x3588, 0x1c47: 0x358d, 0x1c48: 0x3592, 0x1c49: 0x3597, 0x1c4a: 0x359c, 0x1c4b: 0x35a1,
+ 0x1c4c: 0x3514, 0x1c4d: 0x35a6, 0x1c4e: 0x35ab, 0x1c4f: 0x35b0, 0x1c50: 0x35b5, 0x1c51: 0x3533,
+ 0x1c52: 0x3538, 0x1c53: 0x353d, 0x1c54: 0x3542, 0x1c55: 0x3547, 0x1c56: 0x354c, 0x1c57: 0x3551,
+ 0x1c58: 0x3556, 0x1c59: 0x355b, 0x1c5a: 0x3560, 0x1c5b: 0x3565, 0x1c5c: 0x356a, 0x1c5d: 0x356f,
+ 0x1c5e: 0x3574, 0x1c5f: 0x3579, 0x1c60: 0x357e, 0x1c61: 0x3583, 0x1c62: 0x3588, 0x1c63: 0x358d,
+ 0x1c64: 0x3592, 0x1c65: 0x3597, 0x1c66: 0x359c, 0x1c67: 0x35a1, 0x1c68: 0x3514, 0x1c69: 0x35a6,
+ 0x1c6a: 0x35ab, 0x1c6b: 0x35b0, 0x1c6c: 0x35b5, 0x1c6d: 0x3597, 0x1c6e: 0x359c, 0x1c6f: 0x35a1,
+ 0x1c70: 0x3514, 0x1c71: 0x350f, 0x1c72: 0x3519, 0x1c73: 0x333d, 0x1c74: 0x3306, 0x1c75: 0x330b,
+ 0x1c76: 0x3310, 0x1c77: 0x3597, 0x1c78: 0x359c, 0x1c79: 0x35a1, 0x1c7a: 0x333d, 0x1c7b: 0x3342,
+ 0x1c7c: 0x35ba, 0x1c7d: 0x35ba,
+ // Block 0x72, offset 0x1c80
+ 0x1c90: 0x35bf, 0x1c91: 0x35c6,
+ 0x1c92: 0x35c6, 0x1c93: 0x35cd, 0x1c94: 0x35d4, 0x1c95: 0x35db, 0x1c96: 0x35e2, 0x1c97: 0x35e9,
+ 0x1c98: 0x35f0, 0x1c99: 0x35f0, 0x1c9a: 0x35f7, 0x1c9b: 0x35fe, 0x1c9c: 0x3605, 0x1c9d: 0x360c,
+ 0x1c9e: 0x3613, 0x1c9f: 0x361a, 0x1ca0: 0x361a, 0x1ca1: 0x3621, 0x1ca2: 0x3628, 0x1ca3: 0x3628,
+ 0x1ca4: 0x362f, 0x1ca5: 0x362f, 0x1ca6: 0x3636, 0x1ca7: 0x363d, 0x1ca8: 0x363d, 0x1ca9: 0x3644,
+ 0x1caa: 0x364b, 0x1cab: 0x364b, 0x1cac: 0x3652, 0x1cad: 0x3652, 0x1cae: 0x3659, 0x1caf: 0x3660,
+ 0x1cb0: 0x3660, 0x1cb1: 0x3667, 0x1cb2: 0x3667, 0x1cb3: 0x366e, 0x1cb4: 0x3675, 0x1cb5: 0x367c,
+ 0x1cb6: 0x3683, 0x1cb7: 0x3683, 0x1cb8: 0x368a, 0x1cb9: 0x3691, 0x1cba: 0x3698, 0x1cbb: 0x369f,
+ 0x1cbc: 0x36a6, 0x1cbd: 0x36a6, 0x1cbe: 0x36ad, 0x1cbf: 0x36b4,
+ // Block 0x73, offset 0x1cc0
+ 0x1cc0: 0x36bb, 0x1cc1: 0x36c2, 0x1cc2: 0x36c9, 0x1cc3: 0x36d0, 0x1cc4: 0x36d0, 0x1cc5: 0x36d7,
+ 0x1cc6: 0x36d7, 0x1cc7: 0x36de, 0x1cc8: 0x36de, 0x1cc9: 0x36e5, 0x1cca: 0x36ec, 0x1ccb: 0x36f3,
+ 0x1ccc: 0x36fa, 0x1ccd: 0x3701, 0x1cce: 0x3708, 0x1ccf: 0x370f,
+ 0x1cd2: 0x3716, 0x1cd3: 0x371d, 0x1cd4: 0x3724, 0x1cd5: 0x372b, 0x1cd6: 0x3732, 0x1cd7: 0x3739,
+ 0x1cd8: 0x3739, 0x1cd9: 0x3740, 0x1cda: 0x3747, 0x1cdb: 0x374e, 0x1cdc: 0x3755, 0x1cdd: 0x3755,
+ 0x1cde: 0x375c, 0x1cdf: 0x3763, 0x1ce0: 0x376a, 0x1ce1: 0x3771, 0x1ce2: 0x3778, 0x1ce3: 0x377f,
+ 0x1ce4: 0x3786, 0x1ce5: 0x378d, 0x1ce6: 0x3794, 0x1ce7: 0x379b, 0x1ce8: 0x37a2, 0x1ce9: 0x37a9,
+ 0x1cea: 0x37b0, 0x1ceb: 0x37b7, 0x1cec: 0x37be, 0x1ced: 0x37c5, 0x1cee: 0x37cc, 0x1cef: 0x37d3,
+ 0x1cf0: 0x37da, 0x1cf1: 0x37e1, 0x1cf2: 0x37e8, 0x1cf3: 0x37ef, 0x1cf4: 0x36ad, 0x1cf5: 0x36bb,
+ 0x1cf6: 0x37f6, 0x1cf7: 0x37fd, 0x1cf8: 0x3804, 0x1cf9: 0x380b, 0x1cfa: 0x3812, 0x1cfb: 0x3819,
+ 0x1cfc: 0x3812, 0x1cfd: 0x3804, 0x1cfe: 0x3820, 0x1cff: 0x3827,
+ // Block 0x74, offset 0x1d00
+ 0x1d00: 0x382e, 0x1d01: 0x3835, 0x1d02: 0x383c, 0x1d03: 0x3819, 0x1d04: 0x367c, 0x1d05: 0x3636,
+ 0x1d06: 0x3843, 0x1d07: 0x384a,
+ 0x1d30: 0x3851, 0x1d31: 0x3858, 0x1d32: 0x385f, 0x1d33: 0x3868, 0x1d34: 0x3871, 0x1d35: 0x387a,
+ 0x1d36: 0x3883, 0x1d37: 0x388c, 0x1d38: 0x3895, 0x1d39: 0x389e, 0x1d3a: 0x38a5, 0x1d3b: 0x38c7,
+ 0x1d3c: 0x38d7,
+ // Block 0x75, offset 0x1d40
+ 0x1d50: 0x38e0, 0x1d51: 0x38e2,
+ 0x1d52: 0x38e6, 0x1d53: 0x38ea, 0x1d54: 0x04e1, 0x1d55: 0x38ec, 0x1d56: 0x38ee, 0x1d57: 0x38f0,
+ 0x1d58: 0x38f4, 0x1d59: 0x1443,
+ 0x1d70: 0x1440, 0x1d71: 0x38f8, 0x1d72: 0x38fc, 0x1d73: 0x3900, 0x1d74: 0x3900, 0x1d75: 0x149c,
+ 0x1d76: 0x149e, 0x1d77: 0x3902, 0x1d78: 0x3904, 0x1d79: 0x3906, 0x1d7a: 0x390a, 0x1d7b: 0x390e,
+ 0x1d7c: 0x3912, 0x1d7d: 0x3916, 0x1d7e: 0x391a, 0x1d7f: 0x16c3,
+ // Block 0x76, offset 0x1d80
+ 0x1d80: 0x16c7, 0x1d81: 0x391e, 0x1d82: 0x3922, 0x1d83: 0x3926, 0x1d84: 0x392a,
+ 0x1d87: 0x392e, 0x1d88: 0x3930, 0x1d89: 0x146c, 0x1d8a: 0x146c, 0x1d8b: 0x146c,
+ 0x1d8c: 0x146c, 0x1d8d: 0x3900, 0x1d8e: 0x3900, 0x1d8f: 0x3900, 0x1d90: 0x38e0, 0x1d91: 0x38e2,
+ 0x1d92: 0x143e, 0x1d94: 0x04e1, 0x1d95: 0x38ea, 0x1d96: 0x38ee, 0x1d97: 0x38ec,
+ 0x1d98: 0x38f8, 0x1d99: 0x149c, 0x1d9a: 0x149e, 0x1d9b: 0x3902, 0x1d9c: 0x3904, 0x1d9d: 0x3906,
+ 0x1d9e: 0x390a, 0x1d9f: 0x3932, 0x1da0: 0x3934, 0x1da1: 0x3936, 0x1da2: 0x1494, 0x1da3: 0x3938,
+ 0x1da4: 0x393a, 0x1da5: 0x393c, 0x1da6: 0x149a, 0x1da8: 0x393e, 0x1da9: 0x3940,
+ 0x1daa: 0x3942, 0x1dab: 0x3944,
+ 0x1db0: 0x3946, 0x1db1: 0x394a, 0x1db2: 0x394f, 0x1db4: 0x3953,
+ 0x1db6: 0x3957, 0x1db7: 0x395b, 0x1db8: 0x3960, 0x1db9: 0x3964, 0x1dba: 0x3969, 0x1dbb: 0x396d,
+ 0x1dbc: 0x3972, 0x1dbd: 0x3976, 0x1dbe: 0x397b, 0x1dbf: 0x397f,
+ // Block 0x77, offset 0x1dc0
+ 0x1dc0: 0x3984, 0x1dc1: 0x068d, 0x1dc2: 0x068d, 0x1dc3: 0x0692, 0x1dc4: 0x0692, 0x1dc5: 0x0697,
+ 0x1dc6: 0x0697, 0x1dc7: 0x069c, 0x1dc8: 0x069c, 0x1dc9: 0x06a1, 0x1dca: 0x06a1, 0x1dcb: 0x06a1,
+ 0x1dcc: 0x06a1, 0x1dcd: 0x3987, 0x1dce: 0x3987, 0x1dcf: 0x398a, 0x1dd0: 0x398a, 0x1dd1: 0x398a,
+ 0x1dd2: 0x398a, 0x1dd3: 0x398d, 0x1dd4: 0x398d, 0x1dd5: 0x3990, 0x1dd6: 0x3990, 0x1dd7: 0x3990,
+ 0x1dd8: 0x3990, 0x1dd9: 0x3993, 0x1dda: 0x3993, 0x1ddb: 0x3993, 0x1ddc: 0x3993, 0x1ddd: 0x3996,
+ 0x1dde: 0x3996, 0x1ddf: 0x3996, 0x1de0: 0x3996, 0x1de1: 0x3999, 0x1de2: 0x3999, 0x1de3: 0x3999,
+ 0x1de4: 0x3999, 0x1de5: 0x399c, 0x1de6: 0x399c, 0x1de7: 0x399c, 0x1de8: 0x399c, 0x1de9: 0x399f,
+ 0x1dea: 0x399f, 0x1deb: 0x39a2, 0x1dec: 0x39a2, 0x1ded: 0x39a5, 0x1dee: 0x39a5, 0x1def: 0x39a8,
+ 0x1df0: 0x39a8, 0x1df1: 0x39ab, 0x1df2: 0x39ab, 0x1df3: 0x39ab, 0x1df4: 0x39ab, 0x1df5: 0x39ae,
+ 0x1df6: 0x39ae, 0x1df7: 0x39ae, 0x1df8: 0x39ae, 0x1df9: 0x39b1, 0x1dfa: 0x39b1, 0x1dfb: 0x39b1,
+ 0x1dfc: 0x39b1, 0x1dfd: 0x39b4, 0x1dfe: 0x39b4, 0x1dff: 0x39b4,
+ // Block 0x78, offset 0x1e00
+ 0x1e00: 0x39b4, 0x1e01: 0x39b7, 0x1e02: 0x39b7, 0x1e03: 0x39b7, 0x1e04: 0x39b7, 0x1e05: 0x39ba,
+ 0x1e06: 0x39ba, 0x1e07: 0x39ba, 0x1e08: 0x39ba, 0x1e09: 0x39bd, 0x1e0a: 0x39bd, 0x1e0b: 0x39bd,
+ 0x1e0c: 0x39bd, 0x1e0d: 0x39c0, 0x1e0e: 0x39c0, 0x1e0f: 0x39c0, 0x1e10: 0x39c0, 0x1e11: 0x39c3,
+ 0x1e12: 0x39c3, 0x1e13: 0x39c3, 0x1e14: 0x39c3, 0x1e15: 0x39c6, 0x1e16: 0x39c6, 0x1e17: 0x39c6,
+ 0x1e18: 0x39c6, 0x1e19: 0x39c9, 0x1e1a: 0x39c9, 0x1e1b: 0x39c9, 0x1e1c: 0x39c9, 0x1e1d: 0x39cc,
+ 0x1e1e: 0x39cc, 0x1e1f: 0x39cc, 0x1e20: 0x39cc, 0x1e21: 0x39cf, 0x1e22: 0x39cf, 0x1e23: 0x39cf,
+ 0x1e24: 0x39cf, 0x1e25: 0x39d2, 0x1e26: 0x39d2, 0x1e27: 0x39d2, 0x1e28: 0x39d2, 0x1e29: 0x39d5,
+ 0x1e2a: 0x39d5, 0x1e2b: 0x39d5, 0x1e2c: 0x39d5, 0x1e2d: 0x39d8, 0x1e2e: 0x39d8, 0x1e2f: 0x3239,
+ 0x1e30: 0x3239, 0x1e31: 0x39db, 0x1e32: 0x39db, 0x1e33: 0x39db, 0x1e34: 0x39db, 0x1e35: 0x39de,
+ 0x1e36: 0x39de, 0x1e37: 0x39e5, 0x1e38: 0x39e5, 0x1e39: 0x39ec, 0x1e3a: 0x39ec, 0x1e3b: 0x39f3,
+ 0x1e3c: 0x39f3,
+ // Block 0x79, offset 0x1e40
+ 0x1e41: 0x38ec, 0x1e42: 0x39f8, 0x1e43: 0x3932, 0x1e44: 0x3940, 0x1e45: 0x3942,
+ 0x1e46: 0x3934, 0x1e47: 0x39fa, 0x1e48: 0x149c, 0x1e49: 0x149e, 0x1e4a: 0x3936, 0x1e4b: 0x1494,
+ 0x1e4c: 0x38e0, 0x1e4d: 0x3938, 0x1e4e: 0x143e, 0x1e4f: 0x39fc, 0x1e50: 0x1486, 0x1e51: 0x001c,
+ 0x1e52: 0x000d, 0x1e53: 0x000f, 0x1e54: 0x1488, 0x1e55: 0x148a, 0x1e56: 0x148c, 0x1e57: 0x148e,
+ 0x1e58: 0x1490, 0x1e59: 0x1492, 0x1e5a: 0x38ea, 0x1e5b: 0x04e1, 0x1e5c: 0x393a, 0x1e5d: 0x149a,
+ 0x1e5e: 0x393c, 0x1e5f: 0x38ee, 0x1e60: 0x3944, 0x1e61: 0x0906, 0x1e62: 0x090b, 0x1e63: 0x14ad,
+ 0x1e64: 0x090d, 0x1e65: 0x090f, 0x1e66: 0x14d9, 0x1e67: 0x0914, 0x1e68: 0x0916, 0x1e69: 0x0918,
+ 0x1e6a: 0x091a, 0x1e6b: 0x091c, 0x1e6c: 0x091e, 0x1e6d: 0x0920, 0x1e6e: 0x0922, 0x1e6f: 0x0924,
+ 0x1e70: 0x0929, 0x1e71: 0x14c8, 0x1e72: 0x092b, 0x1e73: 0x17f6, 0x1e74: 0x092d, 0x1e75: 0x092f,
+ 0x1e76: 0x155f, 0x1e77: 0x0931, 0x1e78: 0x1570, 0x1e79: 0x17f8, 0x1e7a: 0x14d4, 0x1e7b: 0x392e,
+ 0x1e7c: 0x393e, 0x1e7d: 0x3930, 0x1e7e: 0x39fe, 0x1e7f: 0x3900,
+ // Block 0x7a, offset 0x1e80
+ 0x1e80: 0x13f7, 0x1e81: 0x0007, 0x1e82: 0x093d, 0x1e83: 0x0984, 0x1e84: 0x093f, 0x1e85: 0x0941,
+ 0x1e86: 0x098c, 0x1e87: 0x094c, 0x1e88: 0x0494, 0x1e89: 0x097c, 0x1e8a: 0x0499, 0x1e8b: 0x094e,
+ 0x1e8c: 0x04c5, 0x1e8d: 0x0950, 0x1e8e: 0x14a0, 0x1e8f: 0x001e, 0x1e90: 0x0960, 0x1e91: 0x17fa,
+ 0x1e92: 0x049b, 0x1e93: 0x02c8, 0x1e94: 0x0962, 0x1e95: 0x0964, 0x1e96: 0x096d, 0x1e97: 0x04a6,
+ 0x1e98: 0x04c7, 0x1e99: 0x04a8, 0x1e9a: 0x09df, 0x1e9b: 0x3902, 0x1e9c: 0x3a00, 0x1e9d: 0x3904,
+ 0x1e9e: 0x3a02, 0x1e9f: 0x3a04, 0x1ea0: 0x3a08, 0x1ea1: 0x38e6, 0x1ea2: 0x391e, 0x1ea3: 0x3922,
+ 0x1ea4: 0x38e2, 0x1ea5: 0x3a0c, 0x1ea6: 0x2321, 0x1ea7: 0x3a10, 0x1ea8: 0x3a14, 0x1ea9: 0x3a18,
+ 0x1eaa: 0x3a1c, 0x1eab: 0x3a20, 0x1eac: 0x3a24, 0x1ead: 0x3a28, 0x1eae: 0x3a2c, 0x1eaf: 0x3a30,
+ 0x1eb0: 0x3a34, 0x1eb1: 0x2269, 0x1eb2: 0x226d, 0x1eb3: 0x2271, 0x1eb4: 0x2275, 0x1eb5: 0x2279,
+ 0x1eb6: 0x227d, 0x1eb7: 0x2281, 0x1eb8: 0x2285, 0x1eb9: 0x2289, 0x1eba: 0x228d, 0x1ebb: 0x2291,
+ 0x1ebc: 0x2295, 0x1ebd: 0x2299, 0x1ebe: 0x229d, 0x1ebf: 0x22a1,
+ // Block 0x7b, offset 0x1ec0
+ 0x1ec0: 0x22a5, 0x1ec1: 0x22a9, 0x1ec2: 0x22ad, 0x1ec3: 0x22b1, 0x1ec4: 0x22b5, 0x1ec5: 0x22b9,
+ 0x1ec6: 0x22bd, 0x1ec7: 0x22c1, 0x1ec8: 0x22c5, 0x1ec9: 0x22c9, 0x1eca: 0x22cd, 0x1ecb: 0x22d1,
+ 0x1ecc: 0x22d5, 0x1ecd: 0x22d9, 0x1ece: 0x22dd, 0x1ecf: 0x22e1, 0x1ed0: 0x22e5, 0x1ed1: 0x22e9,
+ 0x1ed2: 0x22ed, 0x1ed3: 0x22f1, 0x1ed4: 0x22f5, 0x1ed5: 0x22f9, 0x1ed6: 0x22fd, 0x1ed7: 0x2301,
+ 0x1ed8: 0x2305, 0x1ed9: 0x2309, 0x1eda: 0x230d, 0x1edb: 0x2311, 0x1edc: 0x2315, 0x1edd: 0x3a38,
+ 0x1ede: 0x3a3c, 0x1edf: 0x3a40, 0x1ee0: 0x1e04, 0x1ee1: 0x1d38, 0x1ee2: 0x1d3c, 0x1ee3: 0x1d40,
+ 0x1ee4: 0x1d44, 0x1ee5: 0x1d48, 0x1ee6: 0x1d4c, 0x1ee7: 0x1d50, 0x1ee8: 0x1d54, 0x1ee9: 0x1d58,
+ 0x1eea: 0x1d5c, 0x1eeb: 0x1d60, 0x1eec: 0x1d64, 0x1eed: 0x1d68, 0x1eee: 0x1d6c, 0x1eef: 0x1d70,
+ 0x1ef0: 0x1d74, 0x1ef1: 0x1d78, 0x1ef2: 0x1d7c, 0x1ef3: 0x1d80, 0x1ef4: 0x1d84, 0x1ef5: 0x1d88,
+ 0x1ef6: 0x1d8c, 0x1ef7: 0x1d90, 0x1ef8: 0x1d94, 0x1ef9: 0x1d98, 0x1efa: 0x1d9c, 0x1efb: 0x1da0,
+ 0x1efc: 0x1da4, 0x1efd: 0x1da8, 0x1efe: 0x1dac,
+ // Block 0x7c, offset 0x1f00
+ 0x1f02: 0x1db0, 0x1f03: 0x1db4, 0x1f04: 0x1db8, 0x1f05: 0x1dbc,
+ 0x1f06: 0x1dc0, 0x1f07: 0x1dc4, 0x1f0a: 0x1dc8, 0x1f0b: 0x1dcc,
+ 0x1f0c: 0x1dd0, 0x1f0d: 0x1dd4, 0x1f0e: 0x1dd8, 0x1f0f: 0x1ddc,
+ 0x1f12: 0x1de0, 0x1f13: 0x1de4, 0x1f14: 0x1de8, 0x1f15: 0x1dec, 0x1f16: 0x1df0, 0x1f17: 0x1df4,
+ 0x1f1a: 0x1df8, 0x1f1b: 0x1dfc, 0x1f1c: 0x1e00,
+ 0x1f20: 0x3a44, 0x1f21: 0x3a47, 0x1f22: 0x3a4a, 0x1f23: 0x0009,
+ 0x1f24: 0x3a4d, 0x1f25: 0x3a50, 0x1f26: 0x3a53, 0x1f28: 0x3a57, 0x1f29: 0x3a5b,
+ 0x1f2a: 0x3a5f, 0x1f2b: 0x3a63, 0x1f2c: 0x3a67, 0x1f2d: 0x3a6b, 0x1f2e: 0x3a6f,
+ // Block 0x7d, offset 0x1f40
+ 0x1f5a: 0x3a73, 0x1f5c: 0x3a7c,
+ 0x1f6b: 0x3a85,
+ // Block 0x7e, offset 0x1f80
+ 0x1f9e: 0x3a8e, 0x1f9f: 0x3a97, 0x1fa0: 0x3aa0, 0x1fa1: 0x3aad, 0x1fa2: 0x3aba, 0x1fa3: 0x3ac7,
+ 0x1fa4: 0x3ad4,
+ // Block 0x7f, offset 0x1fc0
+ 0x1ffb: 0x3ae1,
+ 0x1ffc: 0x3aea, 0x1ffd: 0x3af3, 0x1ffe: 0x3b00, 0x1fff: 0x3b0d,
+ // Block 0x80, offset 0x2000
+ 0x2000: 0x3b1a,
+ // Block 0x81, offset 0x2040
+ 0x2040: 0x0906, 0x2041: 0x090b, 0x2042: 0x14ad, 0x2043: 0x090d, 0x2044: 0x090f, 0x2045: 0x14d9,
+ 0x2046: 0x0914, 0x2047: 0x0916, 0x2048: 0x0918, 0x2049: 0x091a, 0x204a: 0x091c, 0x204b: 0x091e,
+ 0x204c: 0x0920, 0x204d: 0x0922, 0x204e: 0x0924, 0x204f: 0x0929, 0x2050: 0x14c8, 0x2051: 0x092b,
+ 0x2052: 0x17f6, 0x2053: 0x092d, 0x2054: 0x092f, 0x2055: 0x155f, 0x2056: 0x0931, 0x2057: 0x1570,
+ 0x2058: 0x17f8, 0x2059: 0x14d4, 0x205a: 0x0007, 0x205b: 0x093d, 0x205c: 0x0984, 0x205d: 0x093f,
+ 0x205e: 0x0941, 0x205f: 0x098c, 0x2060: 0x094c, 0x2061: 0x0494, 0x2062: 0x097c, 0x2063: 0x0499,
+ 0x2064: 0x094e, 0x2065: 0x04c5, 0x2066: 0x0950, 0x2067: 0x14a0, 0x2068: 0x001e, 0x2069: 0x0960,
+ 0x206a: 0x17fa, 0x206b: 0x049b, 0x206c: 0x02c8, 0x206d: 0x0962, 0x206e: 0x0964, 0x206f: 0x096d,
+ 0x2070: 0x04a6, 0x2071: 0x04c7, 0x2072: 0x04a8, 0x2073: 0x09df, 0x2074: 0x0906, 0x2075: 0x090b,
+ 0x2076: 0x14ad, 0x2077: 0x090d, 0x2078: 0x090f, 0x2079: 0x14d9, 0x207a: 0x0914, 0x207b: 0x0916,
+ 0x207c: 0x0918, 0x207d: 0x091a, 0x207e: 0x091c, 0x207f: 0x091e,
+ // Block 0x82, offset 0x2080
+ 0x2080: 0x0920, 0x2081: 0x0922, 0x2082: 0x0924, 0x2083: 0x0929, 0x2084: 0x14c8, 0x2085: 0x092b,
+ 0x2086: 0x17f6, 0x2087: 0x092d, 0x2088: 0x092f, 0x2089: 0x155f, 0x208a: 0x0931, 0x208b: 0x1570,
+ 0x208c: 0x17f8, 0x208d: 0x14d4, 0x208e: 0x0007, 0x208f: 0x093d, 0x2090: 0x0984, 0x2091: 0x093f,
+ 0x2092: 0x0941, 0x2093: 0x098c, 0x2094: 0x094c, 0x2096: 0x097c, 0x2097: 0x0499,
+ 0x2098: 0x094e, 0x2099: 0x04c5, 0x209a: 0x0950, 0x209b: 0x14a0, 0x209c: 0x001e, 0x209d: 0x0960,
+ 0x209e: 0x17fa, 0x209f: 0x049b, 0x20a0: 0x02c8, 0x20a1: 0x0962, 0x20a2: 0x0964, 0x20a3: 0x096d,
+ 0x20a4: 0x04a6, 0x20a5: 0x04c7, 0x20a6: 0x04a8, 0x20a7: 0x09df, 0x20a8: 0x0906, 0x20a9: 0x090b,
+ 0x20aa: 0x14ad, 0x20ab: 0x090d, 0x20ac: 0x090f, 0x20ad: 0x14d9, 0x20ae: 0x0914, 0x20af: 0x0916,
+ 0x20b0: 0x0918, 0x20b1: 0x091a, 0x20b2: 0x091c, 0x20b3: 0x091e, 0x20b4: 0x0920, 0x20b5: 0x0922,
+ 0x20b6: 0x0924, 0x20b7: 0x0929, 0x20b8: 0x14c8, 0x20b9: 0x092b, 0x20ba: 0x17f6, 0x20bb: 0x092d,
+ 0x20bc: 0x092f, 0x20bd: 0x155f, 0x20be: 0x0931, 0x20bf: 0x1570,
+ // Block 0x83, offset 0x20c0
+ 0x20c0: 0x17f8, 0x20c1: 0x14d4, 0x20c2: 0x0007, 0x20c3: 0x093d, 0x20c4: 0x0984, 0x20c5: 0x093f,
+ 0x20c6: 0x0941, 0x20c7: 0x098c, 0x20c8: 0x094c, 0x20c9: 0x0494, 0x20ca: 0x097c, 0x20cb: 0x0499,
+ 0x20cc: 0x094e, 0x20cd: 0x04c5, 0x20ce: 0x0950, 0x20cf: 0x14a0, 0x20d0: 0x001e, 0x20d1: 0x0960,
+ 0x20d2: 0x17fa, 0x20d3: 0x049b, 0x20d4: 0x02c8, 0x20d5: 0x0962, 0x20d6: 0x0964, 0x20d7: 0x096d,
+ 0x20d8: 0x04a6, 0x20d9: 0x04c7, 0x20da: 0x04a8, 0x20db: 0x09df, 0x20dc: 0x0906,
+ 0x20de: 0x14ad, 0x20df: 0x090d, 0x20e2: 0x0914,
+ 0x20e5: 0x091a, 0x20e6: 0x091c, 0x20e9: 0x0922,
+ 0x20ea: 0x0924, 0x20eb: 0x0929, 0x20ec: 0x14c8, 0x20ee: 0x17f6, 0x20ef: 0x092d,
+ 0x20f0: 0x092f, 0x20f1: 0x155f, 0x20f2: 0x0931, 0x20f3: 0x1570, 0x20f4: 0x17f8, 0x20f5: 0x14d4,
+ 0x20f6: 0x0007, 0x20f7: 0x093d, 0x20f8: 0x0984, 0x20f9: 0x093f, 0x20fb: 0x098c,
+ 0x20fd: 0x0494, 0x20fe: 0x097c, 0x20ff: 0x0499,
+ // Block 0x84, offset 0x2100
+ 0x2100: 0x094e, 0x2101: 0x04c5, 0x2102: 0x0950, 0x2103: 0x14a0, 0x2105: 0x0960,
+ 0x2106: 0x17fa, 0x2107: 0x049b, 0x2108: 0x02c8, 0x2109: 0x0962, 0x210a: 0x0964, 0x210b: 0x096d,
+ 0x210c: 0x04a6, 0x210d: 0x04c7, 0x210e: 0x04a8, 0x210f: 0x09df, 0x2110: 0x0906, 0x2111: 0x090b,
+ 0x2112: 0x14ad, 0x2113: 0x090d, 0x2114: 0x090f, 0x2115: 0x14d9, 0x2116: 0x0914, 0x2117: 0x0916,
+ 0x2118: 0x0918, 0x2119: 0x091a, 0x211a: 0x091c, 0x211b: 0x091e, 0x211c: 0x0920, 0x211d: 0x0922,
+ 0x211e: 0x0924, 0x211f: 0x0929, 0x2120: 0x14c8, 0x2121: 0x092b, 0x2122: 0x17f6, 0x2123: 0x092d,
+ 0x2124: 0x092f, 0x2125: 0x155f, 0x2126: 0x0931, 0x2127: 0x1570, 0x2128: 0x17f8, 0x2129: 0x14d4,
+ 0x212a: 0x0007, 0x212b: 0x093d, 0x212c: 0x0984, 0x212d: 0x093f, 0x212e: 0x0941, 0x212f: 0x098c,
+ 0x2130: 0x094c, 0x2131: 0x0494, 0x2132: 0x097c, 0x2133: 0x0499, 0x2134: 0x094e, 0x2135: 0x04c5,
+ 0x2136: 0x0950, 0x2137: 0x14a0, 0x2138: 0x001e, 0x2139: 0x0960, 0x213a: 0x17fa, 0x213b: 0x049b,
+ 0x213c: 0x02c8, 0x213d: 0x0962, 0x213e: 0x0964, 0x213f: 0x096d,
+ // Block 0x85, offset 0x2140
+ 0x2140: 0x04a6, 0x2141: 0x04c7, 0x2142: 0x04a8, 0x2143: 0x09df, 0x2144: 0x0906, 0x2145: 0x090b,
+ 0x2147: 0x090d, 0x2148: 0x090f, 0x2149: 0x14d9, 0x214a: 0x0914,
+ 0x214d: 0x091a, 0x214e: 0x091c, 0x214f: 0x091e, 0x2150: 0x0920, 0x2151: 0x0922,
+ 0x2152: 0x0924, 0x2153: 0x0929, 0x2154: 0x14c8, 0x2156: 0x17f6, 0x2157: 0x092d,
+ 0x2158: 0x092f, 0x2159: 0x155f, 0x215a: 0x0931, 0x215b: 0x1570, 0x215c: 0x17f8,
+ 0x215e: 0x0007, 0x215f: 0x093d, 0x2160: 0x0984, 0x2161: 0x093f, 0x2162: 0x0941, 0x2163: 0x098c,
+ 0x2164: 0x094c, 0x2165: 0x0494, 0x2166: 0x097c, 0x2167: 0x0499, 0x2168: 0x094e, 0x2169: 0x04c5,
+ 0x216a: 0x0950, 0x216b: 0x14a0, 0x216c: 0x001e, 0x216d: 0x0960, 0x216e: 0x17fa, 0x216f: 0x049b,
+ 0x2170: 0x02c8, 0x2171: 0x0962, 0x2172: 0x0964, 0x2173: 0x096d, 0x2174: 0x04a6, 0x2175: 0x04c7,
+ 0x2176: 0x04a8, 0x2177: 0x09df, 0x2178: 0x0906, 0x2179: 0x090b, 0x217b: 0x090d,
+ 0x217c: 0x090f, 0x217d: 0x14d9, 0x217e: 0x0914,
+ // Block 0x86, offset 0x2180
+ 0x2180: 0x0918, 0x2181: 0x091a, 0x2182: 0x091c, 0x2183: 0x091e, 0x2184: 0x0920,
+ 0x2186: 0x0924, 0x218a: 0x17f6, 0x218b: 0x092d,
+ 0x218c: 0x092f, 0x218d: 0x155f, 0x218e: 0x0931, 0x218f: 0x1570, 0x2190: 0x17f8,
+ 0x2192: 0x0007, 0x2193: 0x093d, 0x2194: 0x0984, 0x2195: 0x093f, 0x2196: 0x0941, 0x2197: 0x098c,
+ 0x2198: 0x094c, 0x2199: 0x0494, 0x219a: 0x097c, 0x219b: 0x0499, 0x219c: 0x094e, 0x219d: 0x04c5,
+ 0x219e: 0x0950, 0x219f: 0x14a0, 0x21a0: 0x001e, 0x21a1: 0x0960, 0x21a2: 0x17fa, 0x21a3: 0x049b,
+ 0x21a4: 0x02c8, 0x21a5: 0x0962, 0x21a6: 0x0964, 0x21a7: 0x096d, 0x21a8: 0x04a6, 0x21a9: 0x04c7,
+ 0x21aa: 0x04a8, 0x21ab: 0x09df, 0x21ac: 0x0906, 0x21ad: 0x090b, 0x21ae: 0x14ad, 0x21af: 0x090d,
+ 0x21b0: 0x090f, 0x21b1: 0x14d9, 0x21b2: 0x0914, 0x21b3: 0x0916, 0x21b4: 0x0918, 0x21b5: 0x091a,
+ 0x21b6: 0x091c, 0x21b7: 0x091e, 0x21b8: 0x0920, 0x21b9: 0x0922, 0x21ba: 0x0924, 0x21bb: 0x0929,
+ 0x21bc: 0x14c8, 0x21bd: 0x092b, 0x21be: 0x17f6, 0x21bf: 0x092d,
+ // Block 0x87, offset 0x21c0
+ 0x21c0: 0x092f, 0x21c1: 0x155f, 0x21c2: 0x0931, 0x21c3: 0x1570, 0x21c4: 0x17f8, 0x21c5: 0x14d4,
+ 0x21c6: 0x0007, 0x21c7: 0x093d, 0x21c8: 0x0984, 0x21c9: 0x093f, 0x21ca: 0x0941, 0x21cb: 0x098c,
+ 0x21cc: 0x094c, 0x21cd: 0x0494, 0x21ce: 0x097c, 0x21cf: 0x0499, 0x21d0: 0x094e, 0x21d1: 0x04c5,
+ 0x21d2: 0x0950, 0x21d3: 0x14a0, 0x21d4: 0x001e, 0x21d5: 0x0960, 0x21d6: 0x17fa, 0x21d7: 0x049b,
+ 0x21d8: 0x02c8, 0x21d9: 0x0962, 0x21da: 0x0964, 0x21db: 0x096d, 0x21dc: 0x04a6, 0x21dd: 0x04c7,
+ 0x21de: 0x04a8, 0x21df: 0x09df, 0x21e0: 0x0906, 0x21e1: 0x090b, 0x21e2: 0x14ad, 0x21e3: 0x090d,
+ 0x21e4: 0x090f, 0x21e5: 0x14d9, 0x21e6: 0x0914, 0x21e7: 0x0916, 0x21e8: 0x0918, 0x21e9: 0x091a,
+ 0x21ea: 0x091c, 0x21eb: 0x091e, 0x21ec: 0x0920, 0x21ed: 0x0922, 0x21ee: 0x0924, 0x21ef: 0x0929,
+ 0x21f0: 0x14c8, 0x21f1: 0x092b, 0x21f2: 0x17f6, 0x21f3: 0x092d, 0x21f4: 0x092f, 0x21f5: 0x155f,
+ 0x21f6: 0x0931, 0x21f7: 0x1570, 0x21f8: 0x17f8, 0x21f9: 0x14d4, 0x21fa: 0x0007, 0x21fb: 0x093d,
+ 0x21fc: 0x0984, 0x21fd: 0x093f, 0x21fe: 0x0941, 0x21ff: 0x098c,
+ // Block 0x88, offset 0x2200
+ 0x2200: 0x094c, 0x2201: 0x0494, 0x2202: 0x097c, 0x2203: 0x0499, 0x2204: 0x094e, 0x2205: 0x04c5,
+ 0x2206: 0x0950, 0x2207: 0x14a0, 0x2208: 0x001e, 0x2209: 0x0960, 0x220a: 0x17fa, 0x220b: 0x049b,
+ 0x220c: 0x02c8, 0x220d: 0x0962, 0x220e: 0x0964, 0x220f: 0x096d, 0x2210: 0x04a6, 0x2211: 0x04c7,
+ 0x2212: 0x04a8, 0x2213: 0x09df, 0x2214: 0x0906, 0x2215: 0x090b, 0x2216: 0x14ad, 0x2217: 0x090d,
+ 0x2218: 0x090f, 0x2219: 0x14d9, 0x221a: 0x0914, 0x221b: 0x0916, 0x221c: 0x0918, 0x221d: 0x091a,
+ 0x221e: 0x091c, 0x221f: 0x091e, 0x2220: 0x0920, 0x2221: 0x0922, 0x2222: 0x0924, 0x2223: 0x0929,
+ 0x2224: 0x14c8, 0x2225: 0x092b, 0x2226: 0x17f6, 0x2227: 0x092d, 0x2228: 0x092f, 0x2229: 0x155f,
+ 0x222a: 0x0931, 0x222b: 0x1570, 0x222c: 0x17f8, 0x222d: 0x14d4, 0x222e: 0x0007, 0x222f: 0x093d,
+ 0x2230: 0x0984, 0x2231: 0x093f, 0x2232: 0x0941, 0x2233: 0x098c, 0x2234: 0x094c, 0x2235: 0x0494,
+ 0x2236: 0x097c, 0x2237: 0x0499, 0x2238: 0x094e, 0x2239: 0x04c5, 0x223a: 0x0950, 0x223b: 0x14a0,
+ 0x223c: 0x001e, 0x223d: 0x0960, 0x223e: 0x17fa, 0x223f: 0x049b,
+ // Block 0x89, offset 0x2240
+ 0x2240: 0x02c8, 0x2241: 0x0962, 0x2242: 0x0964, 0x2243: 0x096d, 0x2244: 0x04a6, 0x2245: 0x04c7,
+ 0x2246: 0x04a8, 0x2247: 0x09df, 0x2248: 0x0906, 0x2249: 0x090b, 0x224a: 0x14ad, 0x224b: 0x090d,
+ 0x224c: 0x090f, 0x224d: 0x14d9, 0x224e: 0x0914, 0x224f: 0x0916, 0x2250: 0x0918, 0x2251: 0x091a,
+ 0x2252: 0x091c, 0x2253: 0x091e, 0x2254: 0x0920, 0x2255: 0x0922, 0x2256: 0x0924, 0x2257: 0x0929,
+ 0x2258: 0x14c8, 0x2259: 0x092b, 0x225a: 0x17f6, 0x225b: 0x092d, 0x225c: 0x092f, 0x225d: 0x155f,
+ 0x225e: 0x0931, 0x225f: 0x1570, 0x2260: 0x17f8, 0x2261: 0x14d4, 0x2262: 0x0007, 0x2263: 0x093d,
+ 0x2264: 0x0984, 0x2265: 0x093f, 0x2266: 0x0941, 0x2267: 0x098c, 0x2268: 0x094c, 0x2269: 0x0494,
+ 0x226a: 0x097c, 0x226b: 0x0499, 0x226c: 0x094e, 0x226d: 0x04c5, 0x226e: 0x0950, 0x226f: 0x14a0,
+ 0x2270: 0x001e, 0x2271: 0x0960, 0x2272: 0x17fa, 0x2273: 0x049b, 0x2274: 0x02c8, 0x2275: 0x0962,
+ 0x2276: 0x0964, 0x2277: 0x096d, 0x2278: 0x04a6, 0x2279: 0x04c7, 0x227a: 0x04a8, 0x227b: 0x09df,
+ 0x227c: 0x0906, 0x227d: 0x090b, 0x227e: 0x14ad, 0x227f: 0x090d,
+ // Block 0x8a, offset 0x2280
+ 0x2280: 0x090f, 0x2281: 0x14d9, 0x2282: 0x0914, 0x2283: 0x0916, 0x2284: 0x0918, 0x2285: 0x091a,
+ 0x2286: 0x091c, 0x2287: 0x091e, 0x2288: 0x0920, 0x2289: 0x0922, 0x228a: 0x0924, 0x228b: 0x0929,
+ 0x228c: 0x14c8, 0x228d: 0x092b, 0x228e: 0x17f6, 0x228f: 0x092d, 0x2290: 0x092f, 0x2291: 0x155f,
+ 0x2292: 0x0931, 0x2293: 0x1570, 0x2294: 0x17f8, 0x2295: 0x14d4, 0x2296: 0x0007, 0x2297: 0x093d,
+ 0x2298: 0x0984, 0x2299: 0x093f, 0x229a: 0x0941, 0x229b: 0x098c, 0x229c: 0x094c, 0x229d: 0x0494,
+ 0x229e: 0x097c, 0x229f: 0x0499, 0x22a0: 0x094e, 0x22a1: 0x04c5, 0x22a2: 0x0950, 0x22a3: 0x14a0,
+ 0x22a4: 0x001e, 0x22a5: 0x0960, 0x22a6: 0x17fa, 0x22a7: 0x049b, 0x22a8: 0x02c8, 0x22a9: 0x0962,
+ 0x22aa: 0x0964, 0x22ab: 0x096d, 0x22ac: 0x04a6, 0x22ad: 0x04c7, 0x22ae: 0x04a8, 0x22af: 0x09df,
+ 0x22b0: 0x0906, 0x22b1: 0x090b, 0x22b2: 0x14ad, 0x22b3: 0x090d, 0x22b4: 0x090f, 0x22b5: 0x14d9,
+ 0x22b6: 0x0914, 0x22b7: 0x0916, 0x22b8: 0x0918, 0x22b9: 0x091a, 0x22ba: 0x091c, 0x22bb: 0x091e,
+ 0x22bc: 0x0920, 0x22bd: 0x0922, 0x22be: 0x0924, 0x22bf: 0x0929,
+ // Block 0x8b, offset 0x22c0
+ 0x22c0: 0x14c8, 0x22c1: 0x092b, 0x22c2: 0x17f6, 0x22c3: 0x092d, 0x22c4: 0x092f, 0x22c5: 0x155f,
+ 0x22c6: 0x0931, 0x22c7: 0x1570, 0x22c8: 0x17f8, 0x22c9: 0x14d4, 0x22ca: 0x0007, 0x22cb: 0x093d,
+ 0x22cc: 0x0984, 0x22cd: 0x093f, 0x22ce: 0x0941, 0x22cf: 0x098c, 0x22d0: 0x094c, 0x22d1: 0x0494,
+ 0x22d2: 0x097c, 0x22d3: 0x0499, 0x22d4: 0x094e, 0x22d5: 0x04c5, 0x22d6: 0x0950, 0x22d7: 0x14a0,
+ 0x22d8: 0x001e, 0x22d9: 0x0960, 0x22da: 0x17fa, 0x22db: 0x049b, 0x22dc: 0x02c8, 0x22dd: 0x0962,
+ 0x22de: 0x0964, 0x22df: 0x096d, 0x22e0: 0x04a6, 0x22e1: 0x04c7, 0x22e2: 0x04a8, 0x22e3: 0x09df,
+ 0x22e4: 0x3b27, 0x22e5: 0x3b2a, 0x22e8: 0x3b2d, 0x22e9: 0x3b30,
+ 0x22ea: 0x14eb, 0x22eb: 0x3b33, 0x22ec: 0x3b36, 0x22ed: 0x3b39, 0x22ee: 0x3b3c, 0x22ef: 0x057b,
+ 0x22f0: 0x3b3f, 0x22f1: 0x3b42, 0x22f2: 0x3b45, 0x22f3: 0x3b48, 0x22f4: 0x3b4b, 0x22f5: 0x3b4e,
+ 0x22f6: 0x3b51, 0x22f7: 0x14ee, 0x22f8: 0x3b54, 0x22f9: 0x057b, 0x22fa: 0x0581, 0x22fb: 0x3b57,
+ 0x22fc: 0x055f, 0x22fd: 0x3b5a, 0x22fe: 0x3b5d, 0x22ff: 0x3b60,
+ // Block 0x8c, offset 0x2300
+ 0x2300: 0x14d6, 0x2301: 0x3b63, 0x2302: 0x3b67, 0x2303: 0x0559, 0x2304: 0x0973, 0x2305: 0x0976,
+ 0x2306: 0x057e, 0x2307: 0x3b6a, 0x2308: 0x3b6d, 0x2309: 0x055c, 0x230a: 0x12fd, 0x230b: 0x0572,
+ 0x230c: 0x3b70, 0x230d: 0x0015, 0x230e: 0x3b73, 0x230f: 0x3b76, 0x2310: 0x3b79, 0x2311: 0x056f,
+ 0x2312: 0x0575, 0x2313: 0x0578, 0x2314: 0x3b7c, 0x2315: 0x3b7f, 0x2316: 0x3b82, 0x2317: 0x056c,
+ 0x2318: 0x0979, 0x2319: 0x3b85, 0x231a: 0x3b88, 0x231b: 0x3b8b, 0x231c: 0x057e, 0x231d: 0x055c,
+ 0x231e: 0x0572, 0x231f: 0x056c, 0x2320: 0x0575, 0x2321: 0x056f, 0x2322: 0x3b2d, 0x2323: 0x3b30,
+ 0x2324: 0x14eb, 0x2325: 0x3b33, 0x2326: 0x3b36, 0x2327: 0x3b39, 0x2328: 0x3b3c, 0x2329: 0x057b,
+ 0x232a: 0x3b3f, 0x232b: 0x3b42, 0x232c: 0x3b45, 0x232d: 0x3b48, 0x232e: 0x3b4b, 0x232f: 0x3b4e,
+ 0x2330: 0x3b51, 0x2331: 0x14ee, 0x2332: 0x3b54, 0x2333: 0x057b, 0x2334: 0x0581, 0x2335: 0x3b57,
+ 0x2336: 0x055f, 0x2337: 0x3b5a, 0x2338: 0x3b5d, 0x2339: 0x3b60, 0x233a: 0x14d6, 0x233b: 0x3b63,
+ 0x233c: 0x3b67, 0x233d: 0x0559, 0x233e: 0x0973, 0x233f: 0x0976,
+ // Block 0x8d, offset 0x2340
+ 0x2340: 0x057e, 0x2341: 0x3b6a, 0x2342: 0x3b6d, 0x2343: 0x055c, 0x2344: 0x12fd, 0x2345: 0x0572,
+ 0x2346: 0x3b70, 0x2347: 0x0015, 0x2348: 0x3b73, 0x2349: 0x3b76, 0x234a: 0x3b79, 0x234b: 0x056f,
+ 0x234c: 0x0575, 0x234d: 0x0578, 0x234e: 0x3b7c, 0x234f: 0x3b7f, 0x2350: 0x3b82, 0x2351: 0x056c,
+ 0x2352: 0x0979, 0x2353: 0x3b85, 0x2354: 0x3b88, 0x2355: 0x3b8b, 0x2356: 0x057e, 0x2357: 0x055c,
+ 0x2358: 0x0572, 0x2359: 0x056c, 0x235a: 0x0575, 0x235b: 0x056f, 0x235c: 0x3b2d, 0x235d: 0x3b30,
+ 0x235e: 0x14eb, 0x235f: 0x3b33, 0x2360: 0x3b36, 0x2361: 0x3b39, 0x2362: 0x3b3c, 0x2363: 0x057b,
+ 0x2364: 0x3b3f, 0x2365: 0x3b42, 0x2366: 0x3b45, 0x2367: 0x3b48, 0x2368: 0x3b4b, 0x2369: 0x3b4e,
+ 0x236a: 0x3b51, 0x236b: 0x14ee, 0x236c: 0x3b54, 0x236d: 0x057b, 0x236e: 0x0581, 0x236f: 0x3b57,
+ 0x2370: 0x055f, 0x2371: 0x3b5a, 0x2372: 0x3b5d, 0x2373: 0x3b60, 0x2374: 0x14d6, 0x2375: 0x3b63,
+ 0x2376: 0x3b67, 0x2377: 0x0559, 0x2378: 0x0973, 0x2379: 0x0976, 0x237a: 0x057e, 0x237b: 0x3b6a,
+ 0x237c: 0x3b6d, 0x237d: 0x055c, 0x237e: 0x12fd, 0x237f: 0x0572,
+ // Block 0x8e, offset 0x2380
+ 0x2380: 0x3b70, 0x2381: 0x0015, 0x2382: 0x3b73, 0x2383: 0x3b76, 0x2384: 0x3b79, 0x2385: 0x056f,
+ 0x2386: 0x0575, 0x2387: 0x0578, 0x2388: 0x3b7c, 0x2389: 0x3b7f, 0x238a: 0x3b82, 0x238b: 0x056c,
+ 0x238c: 0x0979, 0x238d: 0x3b85, 0x238e: 0x3b88, 0x238f: 0x3b8b, 0x2390: 0x057e, 0x2391: 0x055c,
+ 0x2392: 0x0572, 0x2393: 0x056c, 0x2394: 0x0575, 0x2395: 0x056f, 0x2396: 0x3b2d, 0x2397: 0x3b30,
+ 0x2398: 0x14eb, 0x2399: 0x3b33, 0x239a: 0x3b36, 0x239b: 0x3b39, 0x239c: 0x3b3c, 0x239d: 0x057b,
+ 0x239e: 0x3b3f, 0x239f: 0x3b42, 0x23a0: 0x3b45, 0x23a1: 0x3b48, 0x23a2: 0x3b4b, 0x23a3: 0x3b4e,
+ 0x23a4: 0x3b51, 0x23a5: 0x14ee, 0x23a6: 0x3b54, 0x23a7: 0x057b, 0x23a8: 0x0581, 0x23a9: 0x3b57,
+ 0x23aa: 0x055f, 0x23ab: 0x3b5a, 0x23ac: 0x3b5d, 0x23ad: 0x3b60, 0x23ae: 0x14d6, 0x23af: 0x3b63,
+ 0x23b0: 0x3b67, 0x23b1: 0x0559, 0x23b2: 0x0973, 0x23b3: 0x0976, 0x23b4: 0x057e, 0x23b5: 0x3b6a,
+ 0x23b6: 0x3b6d, 0x23b7: 0x055c, 0x23b8: 0x12fd, 0x23b9: 0x0572, 0x23ba: 0x3b70, 0x23bb: 0x0015,
+ 0x23bc: 0x3b73, 0x23bd: 0x3b76, 0x23be: 0x3b79, 0x23bf: 0x056f,
+ // Block 0x8f, offset 0x23c0
+ 0x23c0: 0x0575, 0x23c1: 0x0578, 0x23c2: 0x3b7c, 0x23c3: 0x3b7f, 0x23c4: 0x3b82, 0x23c5: 0x056c,
+ 0x23c6: 0x0979, 0x23c7: 0x3b85, 0x23c8: 0x3b88, 0x23c9: 0x3b8b, 0x23ca: 0x057e, 0x23cb: 0x055c,
+ 0x23cc: 0x0572, 0x23cd: 0x056c, 0x23ce: 0x0575, 0x23cf: 0x056f, 0x23d0: 0x3b2d, 0x23d1: 0x3b30,
+ 0x23d2: 0x14eb, 0x23d3: 0x3b33, 0x23d4: 0x3b36, 0x23d5: 0x3b39, 0x23d6: 0x3b3c, 0x23d7: 0x057b,
+ 0x23d8: 0x3b3f, 0x23d9: 0x3b42, 0x23da: 0x3b45, 0x23db: 0x3b48, 0x23dc: 0x3b4b, 0x23dd: 0x3b4e,
+ 0x23de: 0x3b51, 0x23df: 0x14ee, 0x23e0: 0x3b54, 0x23e1: 0x057b, 0x23e2: 0x0581, 0x23e3: 0x3b57,
+ 0x23e4: 0x055f, 0x23e5: 0x3b5a, 0x23e6: 0x3b5d, 0x23e7: 0x3b60, 0x23e8: 0x14d6, 0x23e9: 0x3b63,
+ 0x23ea: 0x3b67, 0x23eb: 0x0559, 0x23ec: 0x0973, 0x23ed: 0x0976, 0x23ee: 0x057e, 0x23ef: 0x3b6a,
+ 0x23f0: 0x3b6d, 0x23f1: 0x055c, 0x23f2: 0x12fd, 0x23f3: 0x0572, 0x23f4: 0x3b70, 0x23f5: 0x0015,
+ 0x23f6: 0x3b73, 0x23f7: 0x3b76, 0x23f8: 0x3b79, 0x23f9: 0x056f, 0x23fa: 0x0575, 0x23fb: 0x0578,
+ 0x23fc: 0x3b7c, 0x23fd: 0x3b7f, 0x23fe: 0x3b82, 0x23ff: 0x056c,
+ // Block 0x90, offset 0x2400
+ 0x2400: 0x0979, 0x2401: 0x3b85, 0x2402: 0x3b88, 0x2403: 0x3b8b, 0x2404: 0x057e, 0x2405: 0x055c,
+ 0x2406: 0x0572, 0x2407: 0x056c, 0x2408: 0x0575, 0x2409: 0x056f, 0x240a: 0x3b8f, 0x240b: 0x3b92,
+ 0x240e: 0x1486, 0x240f: 0x001c, 0x2410: 0x000d, 0x2411: 0x000f,
+ 0x2412: 0x1488, 0x2413: 0x148a, 0x2414: 0x148c, 0x2415: 0x148e, 0x2416: 0x1490, 0x2417: 0x1492,
+ 0x2418: 0x1486, 0x2419: 0x001c, 0x241a: 0x000d, 0x241b: 0x000f, 0x241c: 0x1488, 0x241d: 0x148a,
+ 0x241e: 0x148c, 0x241f: 0x148e, 0x2420: 0x1490, 0x2421: 0x1492, 0x2422: 0x1486, 0x2423: 0x001c,
+ 0x2424: 0x000d, 0x2425: 0x000f, 0x2426: 0x1488, 0x2427: 0x148a, 0x2428: 0x148c, 0x2429: 0x148e,
+ 0x242a: 0x1490, 0x242b: 0x1492, 0x242c: 0x1486, 0x242d: 0x001c, 0x242e: 0x000d, 0x242f: 0x000f,
+ 0x2430: 0x1488, 0x2431: 0x148a, 0x2432: 0x148c, 0x2433: 0x148e, 0x2434: 0x1490, 0x2435: 0x1492,
+ 0x2436: 0x1486, 0x2437: 0x001c, 0x2438: 0x000d, 0x2439: 0x000f, 0x243a: 0x1488, 0x243b: 0x148a,
+ 0x243c: 0x148c, 0x243d: 0x148e, 0x243e: 0x1490, 0x243f: 0x1492,
+ // Block 0x91, offset 0x2440
+ 0x2440: 0x3b95, 0x2441: 0x3b98, 0x2442: 0x3b9b, 0x2443: 0x3b9e, 0x2444: 0x3ba1, 0x2445: 0x3ba4,
+ 0x2446: 0x3ba7, 0x2447: 0x3baa, 0x2448: 0x3bad, 0x2449: 0x3bb0, 0x244a: 0x3bb3,
+ 0x2450: 0x3bb6, 0x2451: 0x3bba,
+ 0x2452: 0x3bbe, 0x2453: 0x3bc2, 0x2454: 0x3bc6, 0x2455: 0x3bca, 0x2456: 0x3bce, 0x2457: 0x3bd2,
+ 0x2458: 0x3bd6, 0x2459: 0x3bda, 0x245a: 0x3bde, 0x245b: 0x3be2, 0x245c: 0x3be6, 0x245d: 0x3bea,
+ 0x245e: 0x3bee, 0x245f: 0x3bf2, 0x2460: 0x3bf6, 0x2461: 0x3bfa, 0x2462: 0x3bfe, 0x2463: 0x3c02,
+ 0x2464: 0x3c06, 0x2465: 0x3c0a, 0x2466: 0x3c0e, 0x2467: 0x3c12, 0x2468: 0x3c16, 0x2469: 0x3c1a,
+ 0x246a: 0x3c1e, 0x246b: 0x14ad, 0x246c: 0x092b, 0x246d: 0x3c26, 0x246e: 0x3c29,
+ 0x2470: 0x0906, 0x2471: 0x090b, 0x2472: 0x14ad, 0x2473: 0x090d, 0x2474: 0x090f, 0x2475: 0x14d9,
+ 0x2476: 0x0914, 0x2477: 0x0916, 0x2478: 0x0918, 0x2479: 0x091a, 0x247a: 0x091c, 0x247b: 0x091e,
+ 0x247c: 0x0920, 0x247d: 0x0922, 0x247e: 0x0924, 0x247f: 0x0929,
+ // Block 0x92, offset 0x2480
+ 0x2480: 0x14c8, 0x2481: 0x092b, 0x2482: 0x17f6, 0x2483: 0x092d, 0x2484: 0x092f, 0x2485: 0x155f,
+ 0x2486: 0x0931, 0x2487: 0x1570, 0x2488: 0x17f8, 0x2489: 0x14d4, 0x248a: 0x3c2c, 0x248b: 0x293d,
+ 0x248c: 0x3c2f, 0x248d: 0x3c32, 0x248e: 0x3c35, 0x248f: 0x3c39,
+ // Block 0x93, offset 0x24c0
+ 0x24d0: 0x3c3c,
+ // Block 0x94, offset 0x2500
+ 0x2500: 0x3c3f, 0x2501: 0x3c46, 0x2502: 0x2291,
+ 0x2510: 0x1922, 0x2511: 0x3c4d,
+ 0x2512: 0x3c51, 0x2513: 0x1cb3, 0x2514: 0x183e, 0x2515: 0x3c55, 0x2516: 0x3c59, 0x2517: 0x1ed0,
+ 0x2518: 0x3c5d, 0x2519: 0x3c61, 0x251a: 0x3c65, 0x251b: 0x2d49, 0x251c: 0x3c69, 0x251d: 0x3c6d,
+ 0x251e: 0x3c71, 0x251f: 0x3c75, 0x2520: 0x3c79, 0x2521: 0x3c7d, 0x2522: 0x19b2, 0x2523: 0x3c81,
+ 0x2524: 0x3c85, 0x2525: 0x3c89, 0x2526: 0x3c8d, 0x2527: 0x3c91, 0x2528: 0x3c95, 0x2529: 0x1826,
+ 0x252a: 0x1eb0, 0x252b: 0x3c99, 0x252c: 0x21c7, 0x252d: 0x1ebc, 0x252e: 0x21cb, 0x252f: 0x3c9d,
+ 0x2530: 0x1a92, 0x2531: 0x3ca1, 0x2532: 0x3ca5, 0x2533: 0x3ca9, 0x2534: 0x3cad, 0x2535: 0x3cb1,
+ 0x2536: 0x2183, 0x2537: 0x194a, 0x2538: 0x3cb5, 0x2539: 0x3cb9, 0x253a: 0x3cbd,
+ // Block 0x95, offset 0x2540
+ 0x2540: 0x3cc1, 0x2541: 0x3ccb, 0x2542: 0x3cd5, 0x2543: 0x3cdf, 0x2544: 0x3ce9, 0x2545: 0x3cf3,
+ 0x2546: 0x3cfd, 0x2547: 0x3d07, 0x2548: 0x3d11,
+ 0x2550: 0x3d1b, 0x2551: 0x3d1f,
+ // Block 0x96, offset 0x2580
+ 0x2580: 0x3d23, 0x2581: 0x3d27, 0x2582: 0x3d2b, 0x2583: 0x3d2f, 0x2584: 0x3d34, 0x2585: 0x2eb5,
+ 0x2586: 0x3d38, 0x2587: 0x3d3c, 0x2588: 0x3d40, 0x2589: 0x3d44, 0x258a: 0x2eb9, 0x258b: 0x3d48,
+ 0x258c: 0x3d4c, 0x258d: 0x3d50, 0x258e: 0x2ebd, 0x258f: 0x3d55, 0x2590: 0x3d59, 0x2591: 0x3d5d,
+ 0x2592: 0x3d61, 0x2593: 0x3d66, 0x2594: 0x3d6a, 0x2595: 0x3c71, 0x2596: 0x3d6e, 0x2597: 0x3d73,
+ 0x2598: 0x3d77, 0x2599: 0x3d7b, 0x259a: 0x3d7f, 0x259b: 0x2f9a, 0x259c: 0x3d83, 0x259d: 0x1866,
+ 0x259e: 0x3d88, 0x259f: 0x3d8c, 0x25a0: 0x3d90, 0x25a1: 0x3d94, 0x25a2: 0x3cb9, 0x25a3: 0x3d98,
+ 0x25a4: 0x3d9c, 0x25a5: 0x2fae, 0x25a6: 0x2ec1, 0x25a7: 0x2ec5, 0x25a8: 0x2fb2, 0x25a9: 0x3da0,
+ 0x25aa: 0x3da4, 0x25ab: 0x2bf1, 0x25ac: 0x3da8, 0x25ad: 0x2ec9, 0x25ae: 0x3dac, 0x25af: 0x3db0,
+ 0x25b0: 0x3db4, 0x25b1: 0x3db8, 0x25b2: 0x3db8, 0x25b3: 0x3db8, 0x25b4: 0x3dbc, 0x25b5: 0x3dc1,
+ 0x25b6: 0x3dc5, 0x25b7: 0x3dc9, 0x25b8: 0x3dcd, 0x25b9: 0x3dd2, 0x25ba: 0x3dd6, 0x25bb: 0x3dda,
+ 0x25bc: 0x3dde, 0x25bd: 0x3de2, 0x25be: 0x3de6, 0x25bf: 0x3dea,
+ // Block 0x97, offset 0x25c0
+ 0x25c0: 0x3dee, 0x25c1: 0x3df2, 0x25c2: 0x3df6, 0x25c3: 0x3dfa, 0x25c4: 0x3dfe, 0x25c5: 0x3e02,
+ 0x25c6: 0x3e02, 0x25c7: 0x2fba, 0x25c8: 0x3e06, 0x25c9: 0x3e0a, 0x25ca: 0x3e0e, 0x25cb: 0x3e12,
+ 0x25cc: 0x2ed1, 0x25cd: 0x3e16, 0x25ce: 0x3e1a, 0x25cf: 0x3e1e, 0x25d0: 0x2e39, 0x25d1: 0x3e22,
+ 0x25d2: 0x3e26, 0x25d3: 0x3e2a, 0x25d4: 0x3e2e, 0x25d5: 0x3e32, 0x25d6: 0x3e36, 0x25d7: 0x3e3a,
+ 0x25d8: 0x3e3e, 0x25d9: 0x3e42, 0x25da: 0x3e47, 0x25db: 0x3e4b, 0x25dc: 0x3e4f, 0x25dd: 0x3c55,
+ 0x25de: 0x3e53, 0x25df: 0x3e57, 0x25e0: 0x3e5b, 0x25e1: 0x3e60, 0x25e2: 0x3e65, 0x25e3: 0x3e69,
+ 0x25e4: 0x3e6d, 0x25e5: 0x3e71, 0x25e6: 0x3e75, 0x25e7: 0x3e79, 0x25e8: 0x3e7d, 0x25e9: 0x3e81,
+ 0x25ea: 0x3e85, 0x25eb: 0x3e85, 0x25ec: 0x3e89, 0x25ed: 0x3e8e, 0x25ee: 0x3e92, 0x25ef: 0x2be1,
+ 0x25f0: 0x3e96, 0x25f1: 0x3e9a, 0x25f2: 0x3e9f, 0x25f3: 0x3ea3, 0x25f4: 0x3ea7, 0x25f5: 0x18ce,
+ 0x25f6: 0x3eab, 0x25f7: 0x3eaf, 0x25f8: 0x18d6, 0x25f9: 0x3eb3, 0x25fa: 0x3eb7, 0x25fb: 0x3ebb,
+ 0x25fc: 0x3ec0, 0x25fd: 0x3ec4, 0x25fe: 0x3ec9, 0x25ff: 0x3ecd,
+ // Block 0x98, offset 0x2600
+ 0x2600: 0x3ed1, 0x2601: 0x3ed5, 0x2602: 0x3ed9, 0x2603: 0x3edd, 0x2604: 0x3ee1, 0x2605: 0x3ee5,
+ 0x2606: 0x3ee9, 0x2607: 0x3eed, 0x2608: 0x3ef1, 0x2609: 0x3ef5, 0x260a: 0x3efa, 0x260b: 0x3efe,
+ 0x260c: 0x3f02, 0x260d: 0x3f06, 0x260e: 0x2b11, 0x260f: 0x3f0a, 0x2610: 0x18fe, 0x2611: 0x3f0f,
+ 0x2612: 0x3f0f, 0x2613: 0x3f14, 0x2614: 0x3f18, 0x2615: 0x3f18, 0x2616: 0x3f1c, 0x2617: 0x3f20,
+ 0x2618: 0x3f25, 0x2619: 0x3f2a, 0x261a: 0x3f2e, 0x261b: 0x3f32, 0x261c: 0x3f36, 0x261d: 0x3f3a,
+ 0x261e: 0x3f3e, 0x261f: 0x3f42, 0x2620: 0x3f46, 0x2621: 0x3f4a, 0x2622: 0x3f4e, 0x2623: 0x2ee5,
+ 0x2624: 0x3f52, 0x2625: 0x3f57, 0x2626: 0x3f5b, 0x2627: 0x3f5f, 0x2628: 0x2fea, 0x2629: 0x3f5f,
+ 0x262a: 0x3f63, 0x262b: 0x2eed, 0x262c: 0x3f67, 0x262d: 0x3f6b, 0x262e: 0x3f6f, 0x262f: 0x3f73,
+ 0x2630: 0x2ef1, 0x2631: 0x2aa5, 0x2632: 0x3f77, 0x2633: 0x3f7b, 0x2634: 0x3f7f, 0x2635: 0x3f83,
+ 0x2636: 0x3f87, 0x2637: 0x3f8b, 0x2638: 0x3f8f, 0x2639: 0x3f94, 0x263a: 0x3f98, 0x263b: 0x3f9c,
+ 0x263c: 0x3fa0, 0x263d: 0x3fa4, 0x263e: 0x3fa8, 0x263f: 0x3fad,
+ // Block 0x99, offset 0x2640
+ 0x2640: 0x3fb1, 0x2641: 0x3fb5, 0x2642: 0x3fb9, 0x2643: 0x3fbd, 0x2644: 0x3fc1, 0x2645: 0x3fc5,
+ 0x2646: 0x3fc9, 0x2647: 0x3fcd, 0x2648: 0x2ef5, 0x2649: 0x3fd1, 0x264a: 0x3fd5, 0x264b: 0x3fda,
+ 0x264c: 0x3fde, 0x264d: 0x3fe2, 0x264e: 0x3fe6, 0x264f: 0x2efd, 0x2650: 0x3fea, 0x2651: 0x3fee,
+ 0x2652: 0x3ff2, 0x2653: 0x3ff6, 0x2654: 0x3ffa, 0x2655: 0x3ffe, 0x2656: 0x4002, 0x2657: 0x4006,
+ 0x2658: 0x2b15, 0x2659: 0x300a, 0x265a: 0x400a, 0x265b: 0x400e, 0x265c: 0x4012, 0x265d: 0x4016,
+ 0x265e: 0x401b, 0x265f: 0x401f, 0x2660: 0x4023, 0x2661: 0x4027, 0x2662: 0x2f01, 0x2663: 0x402b,
+ 0x2664: 0x4030, 0x2665: 0x4034, 0x2666: 0x4038, 0x2667: 0x30b5, 0x2668: 0x403c, 0x2669: 0x4040,
+ 0x266a: 0x4044, 0x266b: 0x4048, 0x266c: 0x404c, 0x266d: 0x4051, 0x266e: 0x4055, 0x266f: 0x4059,
+ 0x2670: 0x405d, 0x2671: 0x4062, 0x2672: 0x4066, 0x2673: 0x406a, 0x2674: 0x406e, 0x2675: 0x2c25,
+ 0x2676: 0x4072, 0x2677: 0x4076, 0x2678: 0x407b, 0x2679: 0x4080, 0x267a: 0x4085, 0x267b: 0x4089,
+ 0x267c: 0x408e, 0x267d: 0x4092, 0x267e: 0x4096, 0x267f: 0x409a,
+ // Block 0x9a, offset 0x2680
+ 0x2680: 0x409e, 0x2681: 0x2f05, 0x2682: 0x2d71, 0x2683: 0x40a2, 0x2684: 0x40a6, 0x2685: 0x40aa,
+ 0x2686: 0x40ae, 0x2687: 0x40b3, 0x2688: 0x40b7, 0x2689: 0x40bb, 0x268a: 0x40bf, 0x268b: 0x3016,
+ 0x268c: 0x40c3, 0x268d: 0x40c7, 0x268e: 0x40cc, 0x268f: 0x40d0, 0x2690: 0x40d4, 0x2691: 0x40d9,
+ 0x2692: 0x40de, 0x2693: 0x40e2, 0x2694: 0x301a, 0x2695: 0x40e6, 0x2696: 0x40ea, 0x2697: 0x40ee,
+ 0x2698: 0x40f2, 0x2699: 0x40f6, 0x269a: 0x40fa, 0x269b: 0x40fe, 0x269c: 0x4103, 0x269d: 0x4107,
+ 0x269e: 0x410c, 0x269f: 0x4110, 0x26a0: 0x4115, 0x26a1: 0x3022, 0x26a2: 0x4119, 0x26a3: 0x411d,
+ 0x26a4: 0x4122, 0x26a5: 0x4126, 0x26a6: 0x412a, 0x26a7: 0x412f, 0x26a8: 0x4134, 0x26a9: 0x4138,
+ 0x26aa: 0x413c, 0x26ab: 0x4140, 0x26ac: 0x4144, 0x26ad: 0x4144, 0x26ae: 0x4148, 0x26af: 0x414c,
+ 0x26b0: 0x302a, 0x26b1: 0x4150, 0x26b2: 0x4154, 0x26b3: 0x4158, 0x26b4: 0x415c, 0x26b5: 0x4160,
+ 0x26b6: 0x4165, 0x26b7: 0x4169, 0x26b8: 0x2bed, 0x26b9: 0x416e, 0x26ba: 0x4173, 0x26bb: 0x4177,
+ 0x26bc: 0x417c, 0x26bd: 0x4181, 0x26be: 0x4186, 0x26bf: 0x418a,
+ // Block 0x9b, offset 0x26c0
+ 0x26c0: 0x3042, 0x26c1: 0x418e, 0x26c2: 0x4193, 0x26c3: 0x4198, 0x26c4: 0x419d, 0x26c5: 0x41a2,
+ 0x26c6: 0x41a6, 0x26c7: 0x41a6, 0x26c8: 0x3046, 0x26c9: 0x30bd, 0x26ca: 0x41aa, 0x26cb: 0x41ae,
+ 0x26cc: 0x41b2, 0x26cd: 0x41b6, 0x26ce: 0x41bb, 0x26cf: 0x2b59, 0x26d0: 0x304e, 0x26d1: 0x41bf,
+ 0x26d2: 0x41c3, 0x26d3: 0x2f2d, 0x26d4: 0x41c8, 0x26d5: 0x41cd, 0x26d6: 0x2e89, 0x26d7: 0x41d2,
+ 0x26d8: 0x41d6, 0x26d9: 0x2f39, 0x26da: 0x41da, 0x26db: 0x41de, 0x26dc: 0x41e2, 0x26dd: 0x41e7,
+ 0x26de: 0x41e7, 0x26df: 0x41ec, 0x26e0: 0x41f0, 0x26e1: 0x41f4, 0x26e2: 0x41f9, 0x26e3: 0x41fd,
+ 0x26e4: 0x4201, 0x26e5: 0x4205, 0x26e6: 0x420a, 0x26e7: 0x420e, 0x26e8: 0x4212, 0x26e9: 0x4216,
+ 0x26ea: 0x421a, 0x26eb: 0x421e, 0x26ec: 0x4223, 0x26ed: 0x4227, 0x26ee: 0x422b, 0x26ef: 0x422f,
+ 0x26f0: 0x4233, 0x26f1: 0x4237, 0x26f2: 0x423b, 0x26f3: 0x4240, 0x26f4: 0x4245, 0x26f5: 0x4249,
+ 0x26f6: 0x424e, 0x26f7: 0x4252, 0x26f8: 0x4257, 0x26f9: 0x425b, 0x26fa: 0x2f51, 0x26fb: 0x425f,
+ 0x26fc: 0x4264, 0x26fd: 0x4269, 0x26fe: 0x426d, 0x26ff: 0x4272,
+ // Block 0x9c, offset 0x2700
+ 0x2700: 0x4276, 0x2701: 0x427b, 0x2702: 0x427f, 0x2703: 0x4283, 0x2704: 0x4287, 0x2705: 0x428b,
+ 0x2706: 0x428f, 0x2707: 0x4293, 0x2708: 0x4298, 0x2709: 0x429d, 0x270a: 0x42a2, 0x270b: 0x3f14,
+ 0x270c: 0x42a7, 0x270d: 0x42ab, 0x270e: 0x42af, 0x270f: 0x42b3, 0x2710: 0x42b7, 0x2711: 0x42bb,
+ 0x2712: 0x42bf, 0x2713: 0x42c3, 0x2714: 0x42c7, 0x2715: 0x42cb, 0x2716: 0x42cf, 0x2717: 0x42d3,
+ 0x2718: 0x2c31, 0x2719: 0x42d8, 0x271a: 0x42dc, 0x271b: 0x42e0, 0x271c: 0x42e4, 0x271d: 0x42e8,
+ 0x271e: 0x42ec, 0x271f: 0x2f5d, 0x2720: 0x42f0, 0x2721: 0x42f4, 0x2722: 0x42f8, 0x2723: 0x42fc,
+ 0x2724: 0x4300, 0x2725: 0x4305, 0x2726: 0x430a, 0x2727: 0x430f, 0x2728: 0x4313, 0x2729: 0x4317,
+ 0x272a: 0x431b, 0x272b: 0x431f, 0x272c: 0x4324, 0x272d: 0x4328, 0x272e: 0x432d, 0x272f: 0x4331,
+ 0x2730: 0x4335, 0x2731: 0x433a, 0x2732: 0x433f, 0x2733: 0x4343, 0x2734: 0x2b45, 0x2735: 0x4347,
+ 0x2736: 0x434b, 0x2737: 0x434f, 0x2738: 0x4353, 0x2739: 0x4357, 0x273a: 0x435b, 0x273b: 0x306a,
+ 0x273c: 0x435f, 0x273d: 0x4363, 0x273e: 0x4367, 0x273f: 0x436b,
+ // Block 0x9d, offset 0x2740
+ 0x2740: 0x436f, 0x2741: 0x4373, 0x2742: 0x4377, 0x2743: 0x437b, 0x2744: 0x1a66, 0x2745: 0x437f,
+ 0x2746: 0x4384, 0x2747: 0x4388, 0x2748: 0x438c, 0x2749: 0x4390, 0x274a: 0x4394, 0x274b: 0x4398,
+ 0x274c: 0x439d, 0x274d: 0x43a2, 0x274e: 0x43a6, 0x274f: 0x43aa, 0x2750: 0x307e, 0x2751: 0x3082,
+ 0x2752: 0x1a82, 0x2753: 0x43ae, 0x2754: 0x43b3, 0x2755: 0x43b7, 0x2756: 0x43bb, 0x2757: 0x43bf,
+ 0x2758: 0x43c3, 0x2759: 0x43c8, 0x275a: 0x43cd, 0x275b: 0x43d1, 0x275c: 0x43d5, 0x275d: 0x43d9,
+ 0x275e: 0x43de, 0x275f: 0x3086, 0x2760: 0x43e2, 0x2761: 0x43e7, 0x2762: 0x43ec, 0x2763: 0x43f0,
+ 0x2764: 0x43f4, 0x2765: 0x43f8, 0x2766: 0x43fd, 0x2767: 0x4401, 0x2768: 0x4405, 0x2769: 0x4409,
+ 0x276a: 0x440d, 0x276b: 0x4411, 0x276c: 0x4415, 0x276d: 0x4419, 0x276e: 0x441e, 0x276f: 0x4422,
+ 0x2770: 0x4426, 0x2771: 0x442a, 0x2772: 0x442f, 0x2773: 0x4433, 0x2774: 0x4437, 0x2775: 0x443b,
+ 0x2776: 0x443f, 0x2777: 0x4444, 0x2778: 0x4449, 0x2779: 0x444d, 0x277a: 0x4451, 0x277b: 0x4455,
+ 0x277c: 0x445a, 0x277d: 0x445e, 0x277e: 0x309e, 0x277f: 0x309e,
+ // Block 0x9e, offset 0x2780
+ 0x2780: 0x4463, 0x2781: 0x4467, 0x2782: 0x446c, 0x2783: 0x4470, 0x2784: 0x4474, 0x2785: 0x4478,
+ 0x2786: 0x447c, 0x2787: 0x4480, 0x2788: 0x4484, 0x2789: 0x4488, 0x278a: 0x30a2, 0x278b: 0x448d,
+ 0x278c: 0x4491, 0x278d: 0x4495, 0x278e: 0x4499, 0x278f: 0x449d, 0x2790: 0x44a1, 0x2791: 0x44a6,
+ 0x2792: 0x44aa, 0x2793: 0x44af, 0x2794: 0x44b4, 0x2795: 0x1b42, 0x2796: 0x44b9, 0x2797: 0x1b52,
+ 0x2798: 0x44bd, 0x2799: 0x44c1, 0x279a: 0x44c5, 0x279b: 0x44c9, 0x279c: 0x1b66, 0x279d: 0x44cd,
+}
+
+// nfkcDecompLookup: 960 bytes
+// Block 0 is the null block.
+var nfkcDecompLookup = [960]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x0c2: 0x03, 0x0c3: 0x04, 0x0c4: 0x05, 0x0c5: 0x06, 0x0c6: 0x07, 0x0c7: 0x08,
+ 0x0c8: 0x09, 0x0ca: 0x0a, 0x0cb: 0x0b, 0x0cd: 0x0c, 0x0ce: 0x0d, 0x0cf: 0x0e,
+ 0x0d0: 0x0f, 0x0d1: 0x10, 0x0d3: 0x11, 0x0d6: 0x12,
+ 0x0d8: 0x13, 0x0d9: 0x14, 0x0db: 0x15,
+ 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07,
+ 0x0ea: 0x08, 0x0ef: 0x09,
+ 0x0f0: 0x0e,
+ // Block 0x4, offset 0x100
+ 0x124: 0x16, 0x125: 0x17, 0x127: 0x18,
+ 0x128: 0x19, 0x129: 0x1a, 0x12d: 0x1b, 0x12e: 0x1c, 0x12f: 0x1d,
+ 0x131: 0x1e, 0x133: 0x1f, 0x135: 0x20, 0x137: 0x21,
+ 0x138: 0x22, 0x13a: 0x23, 0x13b: 0x24, 0x13c: 0x25, 0x13d: 0x26, 0x13e: 0x27,
+ // Block 0x5, offset 0x140
+ 0x140: 0x28, 0x143: 0x29,
+ 0x16c: 0x2a, 0x16d: 0x2b,
+ 0x174: 0x2c, 0x175: 0x2d, 0x176: 0x2e,
+ 0x178: 0x2f, 0x179: 0x30, 0x17a: 0x31, 0x17b: 0x32, 0x17c: 0x33, 0x17d: 0x34, 0x17e: 0x35, 0x17f: 0x36,
+ // Block 0x6, offset 0x180
+ 0x180: 0x37, 0x181: 0x38, 0x182: 0x39, 0x184: 0x3a, 0x185: 0x3b, 0x186: 0x3c, 0x187: 0x3d,
+ 0x188: 0x3e, 0x189: 0x3f, 0x18a: 0x40, 0x18b: 0x41, 0x18c: 0x42,
+ 0x191: 0x43, 0x192: 0x44, 0x193: 0x45,
+ 0x1a8: 0x46, 0x1a9: 0x47, 0x1ab: 0x48,
+ 0x1b1: 0x49, 0x1b5: 0x4a,
+ 0x1ba: 0x4b, 0x1bb: 0x4c, 0x1bc: 0x4d, 0x1bd: 0x4e, 0x1be: 0x4f, 0x1bf: 0x50,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x51, 0x1c1: 0x52, 0x1c2: 0x53, 0x1c3: 0x54, 0x1c4: 0x55, 0x1c5: 0x56, 0x1c6: 0x57,
+ 0x1c8: 0x58, 0x1c9: 0x59, 0x1ca: 0x5a, 0x1cb: 0x5b, 0x1cc: 0x5c, 0x1cd: 0x5d, 0x1ce: 0x5e, 0x1cf: 0x5f,
+ // Block 0x8, offset 0x200
+ 0x21d: 0x60,
+ // Block 0x9, offset 0x240
+ 0x264: 0x61, 0x265: 0x62, 0x266: 0x63, 0x267: 0x64,
+ 0x268: 0x65, 0x269: 0x66, 0x26a: 0x67, 0x26b: 0x68, 0x26c: 0x69, 0x26d: 0x6a, 0x26e: 0x6b, 0x26f: 0x6c,
+ 0x270: 0x6d, 0x271: 0x6e, 0x272: 0x6f, 0x273: 0x70, 0x274: 0x71, 0x275: 0x72, 0x276: 0x73, 0x277: 0x74,
+ 0x278: 0x75, 0x279: 0x76, 0x27a: 0x77, 0x27b: 0x78, 0x27c: 0x79, 0x27d: 0x7a, 0x27e: 0x7b, 0x27f: 0x7c,
+ // Block 0xa, offset 0x280
+ 0x282: 0x7d,
+ // Block 0xb, offset 0x2c0
+ 0x2c5: 0x7e, 0x2c6: 0x7f, 0x2c7: 0x80,
+ 0x2d0: 0x81, 0x2d1: 0x82, 0x2d2: 0x83, 0x2d3: 0x84, 0x2d4: 0x85, 0x2d5: 0x86, 0x2d6: 0x87, 0x2d7: 0x88,
+ 0x2d8: 0x89, 0x2d9: 0x8a, 0x2da: 0x8b, 0x2db: 0x8c, 0x2dc: 0x8d, 0x2dd: 0x8e, 0x2de: 0x8f, 0x2df: 0x90,
+ // Block 0xc, offset 0x300
+ 0x304: 0x91, 0x305: 0x92, 0x306: 0x93,
+ 0x308: 0x94, 0x309: 0x95,
+ // Block 0xd, offset 0x340
+ 0x360: 0x96, 0x361: 0x97, 0x362: 0x98, 0x363: 0x99, 0x364: 0x9a, 0x365: 0x9b, 0x366: 0x9c, 0x367: 0x9d,
+ 0x368: 0x9e,
+ // Block 0xe, offset 0x380
+ 0x391: 0x0a,
+ 0x39d: 0x0b, 0x39f: 0x0c,
+ 0x3af: 0x0d,
+}
+
+var nfkcDecompTrie = trie{nfkcDecompLookup[:], nfkcDecompValues[:]}
+
+// recompMap: 7448 bytes (entries only)
+var recompMap = map[uint32]uint32{
+ 0x00410300: 0x00C0,
+ 0x00410301: 0x00C1,
+ 0x00410302: 0x00C2,
+ 0x00410303: 0x00C3,
+ 0x00410308: 0x00C4,
+ 0x0041030A: 0x00C5,
+ 0x00430327: 0x00C7,
+ 0x00450300: 0x00C8,
+ 0x00450301: 0x00C9,
+ 0x00450302: 0x00CA,
+ 0x00450308: 0x00CB,
+ 0x00490300: 0x00CC,
+ 0x00490301: 0x00CD,
+ 0x00490302: 0x00CE,
+ 0x00490308: 0x00CF,
+ 0x004E0303: 0x00D1,
+ 0x004F0300: 0x00D2,
+ 0x004F0301: 0x00D3,
+ 0x004F0302: 0x00D4,
+ 0x004F0303: 0x00D5,
+ 0x004F0308: 0x00D6,
+ 0x00550300: 0x00D9,
+ 0x00550301: 0x00DA,
+ 0x00550302: 0x00DB,
+ 0x00550308: 0x00DC,
+ 0x00590301: 0x00DD,
+ 0x00610300: 0x00E0,
+ 0x00610301: 0x00E1,
+ 0x00610302: 0x00E2,
+ 0x00610303: 0x00E3,
+ 0x00610308: 0x00E4,
+ 0x0061030A: 0x00E5,
+ 0x00630327: 0x00E7,
+ 0x00650300: 0x00E8,
+ 0x00650301: 0x00E9,
+ 0x00650302: 0x00EA,
+ 0x00650308: 0x00EB,
+ 0x00690300: 0x00EC,
+ 0x00690301: 0x00ED,
+ 0x00690302: 0x00EE,
+ 0x00690308: 0x00EF,
+ 0x006E0303: 0x00F1,
+ 0x006F0300: 0x00F2,
+ 0x006F0301: 0x00F3,
+ 0x006F0302: 0x00F4,
+ 0x006F0303: 0x00F5,
+ 0x006F0308: 0x00F6,
+ 0x00750300: 0x00F9,
+ 0x00750301: 0x00FA,
+ 0x00750302: 0x00FB,
+ 0x00750308: 0x00FC,
+ 0x00790301: 0x00FD,
+ 0x00790308: 0x00FF,
+ 0x00410304: 0x0100,
+ 0x00610304: 0x0101,
+ 0x00410306: 0x0102,
+ 0x00610306: 0x0103,
+ 0x00410328: 0x0104,
+ 0x00610328: 0x0105,
+ 0x00430301: 0x0106,
+ 0x00630301: 0x0107,
+ 0x00430302: 0x0108,
+ 0x00630302: 0x0109,
+ 0x00430307: 0x010A,
+ 0x00630307: 0x010B,
+ 0x0043030C: 0x010C,
+ 0x0063030C: 0x010D,
+ 0x0044030C: 0x010E,
+ 0x0064030C: 0x010F,
+ 0x00450304: 0x0112,
+ 0x00650304: 0x0113,
+ 0x00450306: 0x0114,
+ 0x00650306: 0x0115,
+ 0x00450307: 0x0116,
+ 0x00650307: 0x0117,
+ 0x00450328: 0x0118,
+ 0x00650328: 0x0119,
+ 0x0045030C: 0x011A,
+ 0x0065030C: 0x011B,
+ 0x00470302: 0x011C,
+ 0x00670302: 0x011D,
+ 0x00470306: 0x011E,
+ 0x00670306: 0x011F,
+ 0x00470307: 0x0120,
+ 0x00670307: 0x0121,
+ 0x00470327: 0x0122,
+ 0x00670327: 0x0123,
+ 0x00480302: 0x0124,
+ 0x00680302: 0x0125,
+ 0x00490303: 0x0128,
+ 0x00690303: 0x0129,
+ 0x00490304: 0x012A,
+ 0x00690304: 0x012B,
+ 0x00490306: 0x012C,
+ 0x00690306: 0x012D,
+ 0x00490328: 0x012E,
+ 0x00690328: 0x012F,
+ 0x00490307: 0x0130,
+ 0x004A0302: 0x0134,
+ 0x006A0302: 0x0135,
+ 0x004B0327: 0x0136,
+ 0x006B0327: 0x0137,
+ 0x004C0301: 0x0139,
+ 0x006C0301: 0x013A,
+ 0x004C0327: 0x013B,
+ 0x006C0327: 0x013C,
+ 0x004C030C: 0x013D,
+ 0x006C030C: 0x013E,
+ 0x004E0301: 0x0143,
+ 0x006E0301: 0x0144,
+ 0x004E0327: 0x0145,
+ 0x006E0327: 0x0146,
+ 0x004E030C: 0x0147,
+ 0x006E030C: 0x0148,
+ 0x004F0304: 0x014C,
+ 0x006F0304: 0x014D,
+ 0x004F0306: 0x014E,
+ 0x006F0306: 0x014F,
+ 0x004F030B: 0x0150,
+ 0x006F030B: 0x0151,
+ 0x00520301: 0x0154,
+ 0x00720301: 0x0155,
+ 0x00520327: 0x0156,
+ 0x00720327: 0x0157,
+ 0x0052030C: 0x0158,
+ 0x0072030C: 0x0159,
+ 0x00530301: 0x015A,
+ 0x00730301: 0x015B,
+ 0x00530302: 0x015C,
+ 0x00730302: 0x015D,
+ 0x00530327: 0x015E,
+ 0x00730327: 0x015F,
+ 0x0053030C: 0x0160,
+ 0x0073030C: 0x0161,
+ 0x00540327: 0x0162,
+ 0x00740327: 0x0163,
+ 0x0054030C: 0x0164,
+ 0x0074030C: 0x0165,
+ 0x00550303: 0x0168,
+ 0x00750303: 0x0169,
+ 0x00550304: 0x016A,
+ 0x00750304: 0x016B,
+ 0x00550306: 0x016C,
+ 0x00750306: 0x016D,
+ 0x0055030A: 0x016E,
+ 0x0075030A: 0x016F,
+ 0x0055030B: 0x0170,
+ 0x0075030B: 0x0171,
+ 0x00550328: 0x0172,
+ 0x00750328: 0x0173,
+ 0x00570302: 0x0174,
+ 0x00770302: 0x0175,
+ 0x00590302: 0x0176,
+ 0x00790302: 0x0177,
+ 0x00590308: 0x0178,
+ 0x005A0301: 0x0179,
+ 0x007A0301: 0x017A,
+ 0x005A0307: 0x017B,
+ 0x007A0307: 0x017C,
+ 0x005A030C: 0x017D,
+ 0x007A030C: 0x017E,
+ 0x004F031B: 0x01A0,
+ 0x006F031B: 0x01A1,
+ 0x0055031B: 0x01AF,
+ 0x0075031B: 0x01B0,
+ 0x0041030C: 0x01CD,
+ 0x0061030C: 0x01CE,
+ 0x0049030C: 0x01CF,
+ 0x0069030C: 0x01D0,
+ 0x004F030C: 0x01D1,
+ 0x006F030C: 0x01D2,
+ 0x0055030C: 0x01D3,
+ 0x0075030C: 0x01D4,
+ 0x00DC0304: 0x01D5,
+ 0x00FC0304: 0x01D6,
+ 0x00DC0301: 0x01D7,
+ 0x00FC0301: 0x01D8,
+ 0x00DC030C: 0x01D9,
+ 0x00FC030C: 0x01DA,
+ 0x00DC0300: 0x01DB,
+ 0x00FC0300: 0x01DC,
+ 0x00C40304: 0x01DE,
+ 0x00E40304: 0x01DF,
+ 0x02260304: 0x01E0,
+ 0x02270304: 0x01E1,
+ 0x00C60304: 0x01E2,
+ 0x00E60304: 0x01E3,
+ 0x0047030C: 0x01E6,
+ 0x0067030C: 0x01E7,
+ 0x004B030C: 0x01E8,
+ 0x006B030C: 0x01E9,
+ 0x004F0328: 0x01EA,
+ 0x006F0328: 0x01EB,
+ 0x01EA0304: 0x01EC,
+ 0x01EB0304: 0x01ED,
+ 0x01B7030C: 0x01EE,
+ 0x0292030C: 0x01EF,
+ 0x006A030C: 0x01F0,
+ 0x00470301: 0x01F4,
+ 0x00670301: 0x01F5,
+ 0x004E0300: 0x01F8,
+ 0x006E0300: 0x01F9,
+ 0x00C50301: 0x01FA,
+ 0x00E50301: 0x01FB,
+ 0x00C60301: 0x01FC,
+ 0x00E60301: 0x01FD,
+ 0x00D80301: 0x01FE,
+ 0x00F80301: 0x01FF,
+ 0x0041030F: 0x0200,
+ 0x0061030F: 0x0201,
+ 0x00410311: 0x0202,
+ 0x00610311: 0x0203,
+ 0x0045030F: 0x0204,
+ 0x0065030F: 0x0205,
+ 0x00450311: 0x0206,
+ 0x00650311: 0x0207,
+ 0x0049030F: 0x0208,
+ 0x0069030F: 0x0209,
+ 0x00490311: 0x020A,
+ 0x00690311: 0x020B,
+ 0x004F030F: 0x020C,
+ 0x006F030F: 0x020D,
+ 0x004F0311: 0x020E,
+ 0x006F0311: 0x020F,
+ 0x0052030F: 0x0210,
+ 0x0072030F: 0x0211,
+ 0x00520311: 0x0212,
+ 0x00720311: 0x0213,
+ 0x0055030F: 0x0214,
+ 0x0075030F: 0x0215,
+ 0x00550311: 0x0216,
+ 0x00750311: 0x0217,
+ 0x00530326: 0x0218,
+ 0x00730326: 0x0219,
+ 0x00540326: 0x021A,
+ 0x00740326: 0x021B,
+ 0x0048030C: 0x021E,
+ 0x0068030C: 0x021F,
+ 0x00410307: 0x0226,
+ 0x00610307: 0x0227,
+ 0x00450327: 0x0228,
+ 0x00650327: 0x0229,
+ 0x00D60304: 0x022A,
+ 0x00F60304: 0x022B,
+ 0x00D50304: 0x022C,
+ 0x00F50304: 0x022D,
+ 0x004F0307: 0x022E,
+ 0x006F0307: 0x022F,
+ 0x022E0304: 0x0230,
+ 0x022F0304: 0x0231,
+ 0x00590304: 0x0232,
+ 0x00790304: 0x0233,
+ 0x00A80301: 0x0385,
+ 0x03910301: 0x0386,
+ 0x03950301: 0x0388,
+ 0x03970301: 0x0389,
+ 0x03990301: 0x038A,
+ 0x039F0301: 0x038C,
+ 0x03A50301: 0x038E,
+ 0x03A90301: 0x038F,
+ 0x03CA0301: 0x0390,
+ 0x03990308: 0x03AA,
+ 0x03A50308: 0x03AB,
+ 0x03B10301: 0x03AC,
+ 0x03B50301: 0x03AD,
+ 0x03B70301: 0x03AE,
+ 0x03B90301: 0x03AF,
+ 0x03CB0301: 0x03B0,
+ 0x03B90308: 0x03CA,
+ 0x03C50308: 0x03CB,
+ 0x03BF0301: 0x03CC,
+ 0x03C50301: 0x03CD,
+ 0x03C90301: 0x03CE,
+ 0x03D20301: 0x03D3,
+ 0x03D20308: 0x03D4,
+ 0x04150300: 0x0400,
+ 0x04150308: 0x0401,
+ 0x04130301: 0x0403,
+ 0x04060308: 0x0407,
+ 0x041A0301: 0x040C,
+ 0x04180300: 0x040D,
+ 0x04230306: 0x040E,
+ 0x04180306: 0x0419,
+ 0x04380306: 0x0439,
+ 0x04350300: 0x0450,
+ 0x04350308: 0x0451,
+ 0x04330301: 0x0453,
+ 0x04560308: 0x0457,
+ 0x043A0301: 0x045C,
+ 0x04380300: 0x045D,
+ 0x04430306: 0x045E,
+ 0x0474030F: 0x0476,
+ 0x0475030F: 0x0477,
+ 0x04160306: 0x04C1,
+ 0x04360306: 0x04C2,
+ 0x04100306: 0x04D0,
+ 0x04300306: 0x04D1,
+ 0x04100308: 0x04D2,
+ 0x04300308: 0x04D3,
+ 0x04150306: 0x04D6,
+ 0x04350306: 0x04D7,
+ 0x04D80308: 0x04DA,
+ 0x04D90308: 0x04DB,
+ 0x04160308: 0x04DC,
+ 0x04360308: 0x04DD,
+ 0x04170308: 0x04DE,
+ 0x04370308: 0x04DF,
+ 0x04180304: 0x04E2,
+ 0x04380304: 0x04E3,
+ 0x04180308: 0x04E4,
+ 0x04380308: 0x04E5,
+ 0x041E0308: 0x04E6,
+ 0x043E0308: 0x04E7,
+ 0x04E80308: 0x04EA,
+ 0x04E90308: 0x04EB,
+ 0x042D0308: 0x04EC,
+ 0x044D0308: 0x04ED,
+ 0x04230304: 0x04EE,
+ 0x04430304: 0x04EF,
+ 0x04230308: 0x04F0,
+ 0x04430308: 0x04F1,
+ 0x0423030B: 0x04F2,
+ 0x0443030B: 0x04F3,
+ 0x04270308: 0x04F4,
+ 0x04470308: 0x04F5,
+ 0x042B0308: 0x04F8,
+ 0x044B0308: 0x04F9,
+ 0x06270653: 0x0622,
+ 0x06270654: 0x0623,
+ 0x06480654: 0x0624,
+ 0x06270655: 0x0625,
+ 0x064A0654: 0x0626,
+ 0x06D50654: 0x06C0,
+ 0x06C10654: 0x06C2,
+ 0x06D20654: 0x06D3,
+ 0x0928093C: 0x0929,
+ 0x0930093C: 0x0931,
+ 0x0933093C: 0x0934,
+ 0x09C709BE: 0x09CB,
+ 0x09C709D7: 0x09CC,
+ 0x0B470B56: 0x0B48,
+ 0x0B470B3E: 0x0B4B,
+ 0x0B470B57: 0x0B4C,
+ 0x0B920BD7: 0x0B94,
+ 0x0BC60BBE: 0x0BCA,
+ 0x0BC70BBE: 0x0BCB,
+ 0x0BC60BD7: 0x0BCC,
+ 0x0C460C56: 0x0C48,
+ 0x0CBF0CD5: 0x0CC0,
+ 0x0CC60CD5: 0x0CC7,
+ 0x0CC60CD6: 0x0CC8,
+ 0x0CC60CC2: 0x0CCA,
+ 0x0CCA0CD5: 0x0CCB,
+ 0x0D460D3E: 0x0D4A,
+ 0x0D470D3E: 0x0D4B,
+ 0x0D460D57: 0x0D4C,
+ 0x0DD90DCA: 0x0DDA,
+ 0x0DD90DCF: 0x0DDC,
+ 0x0DDC0DCA: 0x0DDD,
+ 0x0DD90DDF: 0x0DDE,
+ 0x1025102E: 0x1026,
+ 0x1B051B35: 0x1B06,
+ 0x1B071B35: 0x1B08,
+ 0x1B091B35: 0x1B0A,
+ 0x1B0B1B35: 0x1B0C,
+ 0x1B0D1B35: 0x1B0E,
+ 0x1B111B35: 0x1B12,
+ 0x1B3A1B35: 0x1B3B,
+ 0x1B3C1B35: 0x1B3D,
+ 0x1B3E1B35: 0x1B40,
+ 0x1B3F1B35: 0x1B41,
+ 0x1B421B35: 0x1B43,
+ 0x00410325: 0x1E00,
+ 0x00610325: 0x1E01,
+ 0x00420307: 0x1E02,
+ 0x00620307: 0x1E03,
+ 0x00420323: 0x1E04,
+ 0x00620323: 0x1E05,
+ 0x00420331: 0x1E06,
+ 0x00620331: 0x1E07,
+ 0x00C70301: 0x1E08,
+ 0x00E70301: 0x1E09,
+ 0x00440307: 0x1E0A,
+ 0x00640307: 0x1E0B,
+ 0x00440323: 0x1E0C,
+ 0x00640323: 0x1E0D,
+ 0x00440331: 0x1E0E,
+ 0x00640331: 0x1E0F,
+ 0x00440327: 0x1E10,
+ 0x00640327: 0x1E11,
+ 0x0044032D: 0x1E12,
+ 0x0064032D: 0x1E13,
+ 0x01120300: 0x1E14,
+ 0x01130300: 0x1E15,
+ 0x01120301: 0x1E16,
+ 0x01130301: 0x1E17,
+ 0x0045032D: 0x1E18,
+ 0x0065032D: 0x1E19,
+ 0x00450330: 0x1E1A,
+ 0x00650330: 0x1E1B,
+ 0x02280306: 0x1E1C,
+ 0x02290306: 0x1E1D,
+ 0x00460307: 0x1E1E,
+ 0x00660307: 0x1E1F,
+ 0x00470304: 0x1E20,
+ 0x00670304: 0x1E21,
+ 0x00480307: 0x1E22,
+ 0x00680307: 0x1E23,
+ 0x00480323: 0x1E24,
+ 0x00680323: 0x1E25,
+ 0x00480308: 0x1E26,
+ 0x00680308: 0x1E27,
+ 0x00480327: 0x1E28,
+ 0x00680327: 0x1E29,
+ 0x0048032E: 0x1E2A,
+ 0x0068032E: 0x1E2B,
+ 0x00490330: 0x1E2C,
+ 0x00690330: 0x1E2D,
+ 0x00CF0301: 0x1E2E,
+ 0x00EF0301: 0x1E2F,
+ 0x004B0301: 0x1E30,
+ 0x006B0301: 0x1E31,
+ 0x004B0323: 0x1E32,
+ 0x006B0323: 0x1E33,
+ 0x004B0331: 0x1E34,
+ 0x006B0331: 0x1E35,
+ 0x004C0323: 0x1E36,
+ 0x006C0323: 0x1E37,
+ 0x1E360304: 0x1E38,
+ 0x1E370304: 0x1E39,
+ 0x004C0331: 0x1E3A,
+ 0x006C0331: 0x1E3B,
+ 0x004C032D: 0x1E3C,
+ 0x006C032D: 0x1E3D,
+ 0x004D0301: 0x1E3E,
+ 0x006D0301: 0x1E3F,
+ 0x004D0307: 0x1E40,
+ 0x006D0307: 0x1E41,
+ 0x004D0323: 0x1E42,
+ 0x006D0323: 0x1E43,
+ 0x004E0307: 0x1E44,
+ 0x006E0307: 0x1E45,
+ 0x004E0323: 0x1E46,
+ 0x006E0323: 0x1E47,
+ 0x004E0331: 0x1E48,
+ 0x006E0331: 0x1E49,
+ 0x004E032D: 0x1E4A,
+ 0x006E032D: 0x1E4B,
+ 0x00D50301: 0x1E4C,
+ 0x00F50301: 0x1E4D,
+ 0x00D50308: 0x1E4E,
+ 0x00F50308: 0x1E4F,
+ 0x014C0300: 0x1E50,
+ 0x014D0300: 0x1E51,
+ 0x014C0301: 0x1E52,
+ 0x014D0301: 0x1E53,
+ 0x00500301: 0x1E54,
+ 0x00700301: 0x1E55,
+ 0x00500307: 0x1E56,
+ 0x00700307: 0x1E57,
+ 0x00520307: 0x1E58,
+ 0x00720307: 0x1E59,
+ 0x00520323: 0x1E5A,
+ 0x00720323: 0x1E5B,
+ 0x1E5A0304: 0x1E5C,
+ 0x1E5B0304: 0x1E5D,
+ 0x00520331: 0x1E5E,
+ 0x00720331: 0x1E5F,
+ 0x00530307: 0x1E60,
+ 0x00730307: 0x1E61,
+ 0x00530323: 0x1E62,
+ 0x00730323: 0x1E63,
+ 0x015A0307: 0x1E64,
+ 0x015B0307: 0x1E65,
+ 0x01600307: 0x1E66,
+ 0x01610307: 0x1E67,
+ 0x1E620307: 0x1E68,
+ 0x1E630307: 0x1E69,
+ 0x00540307: 0x1E6A,
+ 0x00740307: 0x1E6B,
+ 0x00540323: 0x1E6C,
+ 0x00740323: 0x1E6D,
+ 0x00540331: 0x1E6E,
+ 0x00740331: 0x1E6F,
+ 0x0054032D: 0x1E70,
+ 0x0074032D: 0x1E71,
+ 0x00550324: 0x1E72,
+ 0x00750324: 0x1E73,
+ 0x00550330: 0x1E74,
+ 0x00750330: 0x1E75,
+ 0x0055032D: 0x1E76,
+ 0x0075032D: 0x1E77,
+ 0x01680301: 0x1E78,
+ 0x01690301: 0x1E79,
+ 0x016A0308: 0x1E7A,
+ 0x016B0308: 0x1E7B,
+ 0x00560303: 0x1E7C,
+ 0x00760303: 0x1E7D,
+ 0x00560323: 0x1E7E,
+ 0x00760323: 0x1E7F,
+ 0x00570300: 0x1E80,
+ 0x00770300: 0x1E81,
+ 0x00570301: 0x1E82,
+ 0x00770301: 0x1E83,
+ 0x00570308: 0x1E84,
+ 0x00770308: 0x1E85,
+ 0x00570307: 0x1E86,
+ 0x00770307: 0x1E87,
+ 0x00570323: 0x1E88,
+ 0x00770323: 0x1E89,
+ 0x00580307: 0x1E8A,
+ 0x00780307: 0x1E8B,
+ 0x00580308: 0x1E8C,
+ 0x00780308: 0x1E8D,
+ 0x00590307: 0x1E8E,
+ 0x00790307: 0x1E8F,
+ 0x005A0302: 0x1E90,
+ 0x007A0302: 0x1E91,
+ 0x005A0323: 0x1E92,
+ 0x007A0323: 0x1E93,
+ 0x005A0331: 0x1E94,
+ 0x007A0331: 0x1E95,
+ 0x00680331: 0x1E96,
+ 0x00740308: 0x1E97,
+ 0x0077030A: 0x1E98,
+ 0x0079030A: 0x1E99,
+ 0x017F0307: 0x1E9B,
+ 0x00410323: 0x1EA0,
+ 0x00610323: 0x1EA1,
+ 0x00410309: 0x1EA2,
+ 0x00610309: 0x1EA3,
+ 0x00C20301: 0x1EA4,
+ 0x00E20301: 0x1EA5,
+ 0x00C20300: 0x1EA6,
+ 0x00E20300: 0x1EA7,
+ 0x00C20309: 0x1EA8,
+ 0x00E20309: 0x1EA9,
+ 0x00C20303: 0x1EAA,
+ 0x00E20303: 0x1EAB,
+ 0x1EA00302: 0x1EAC,
+ 0x1EA10302: 0x1EAD,
+ 0x01020301: 0x1EAE,
+ 0x01030301: 0x1EAF,
+ 0x01020300: 0x1EB0,
+ 0x01030300: 0x1EB1,
+ 0x01020309: 0x1EB2,
+ 0x01030309: 0x1EB3,
+ 0x01020303: 0x1EB4,
+ 0x01030303: 0x1EB5,
+ 0x1EA00306: 0x1EB6,
+ 0x1EA10306: 0x1EB7,
+ 0x00450323: 0x1EB8,
+ 0x00650323: 0x1EB9,
+ 0x00450309: 0x1EBA,
+ 0x00650309: 0x1EBB,
+ 0x00450303: 0x1EBC,
+ 0x00650303: 0x1EBD,
+ 0x00CA0301: 0x1EBE,
+ 0x00EA0301: 0x1EBF,
+ 0x00CA0300: 0x1EC0,
+ 0x00EA0300: 0x1EC1,
+ 0x00CA0309: 0x1EC2,
+ 0x00EA0309: 0x1EC3,
+ 0x00CA0303: 0x1EC4,
+ 0x00EA0303: 0x1EC5,
+ 0x1EB80302: 0x1EC6,
+ 0x1EB90302: 0x1EC7,
+ 0x00490309: 0x1EC8,
+ 0x00690309: 0x1EC9,
+ 0x00490323: 0x1ECA,
+ 0x00690323: 0x1ECB,
+ 0x004F0323: 0x1ECC,
+ 0x006F0323: 0x1ECD,
+ 0x004F0309: 0x1ECE,
+ 0x006F0309: 0x1ECF,
+ 0x00D40301: 0x1ED0,
+ 0x00F40301: 0x1ED1,
+ 0x00D40300: 0x1ED2,
+ 0x00F40300: 0x1ED3,
+ 0x00D40309: 0x1ED4,
+ 0x00F40309: 0x1ED5,
+ 0x00D40303: 0x1ED6,
+ 0x00F40303: 0x1ED7,
+ 0x1ECC0302: 0x1ED8,
+ 0x1ECD0302: 0x1ED9,
+ 0x01A00301: 0x1EDA,
+ 0x01A10301: 0x1EDB,
+ 0x01A00300: 0x1EDC,
+ 0x01A10300: 0x1EDD,
+ 0x01A00309: 0x1EDE,
+ 0x01A10309: 0x1EDF,
+ 0x01A00303: 0x1EE0,
+ 0x01A10303: 0x1EE1,
+ 0x01A00323: 0x1EE2,
+ 0x01A10323: 0x1EE3,
+ 0x00550323: 0x1EE4,
+ 0x00750323: 0x1EE5,
+ 0x00550309: 0x1EE6,
+ 0x00750309: 0x1EE7,
+ 0x01AF0301: 0x1EE8,
+ 0x01B00301: 0x1EE9,
+ 0x01AF0300: 0x1EEA,
+ 0x01B00300: 0x1EEB,
+ 0x01AF0309: 0x1EEC,
+ 0x01B00309: 0x1EED,
+ 0x01AF0303: 0x1EEE,
+ 0x01B00303: 0x1EEF,
+ 0x01AF0323: 0x1EF0,
+ 0x01B00323: 0x1EF1,
+ 0x00590300: 0x1EF2,
+ 0x00790300: 0x1EF3,
+ 0x00590323: 0x1EF4,
+ 0x00790323: 0x1EF5,
+ 0x00590309: 0x1EF6,
+ 0x00790309: 0x1EF7,
+ 0x00590303: 0x1EF8,
+ 0x00790303: 0x1EF9,
+ 0x03B10313: 0x1F00,
+ 0x03B10314: 0x1F01,
+ 0x1F000300: 0x1F02,
+ 0x1F010300: 0x1F03,
+ 0x1F000301: 0x1F04,
+ 0x1F010301: 0x1F05,
+ 0x1F000342: 0x1F06,
+ 0x1F010342: 0x1F07,
+ 0x03910313: 0x1F08,
+ 0x03910314: 0x1F09,
+ 0x1F080300: 0x1F0A,
+ 0x1F090300: 0x1F0B,
+ 0x1F080301: 0x1F0C,
+ 0x1F090301: 0x1F0D,
+ 0x1F080342: 0x1F0E,
+ 0x1F090342: 0x1F0F,
+ 0x03B50313: 0x1F10,
+ 0x03B50314: 0x1F11,
+ 0x1F100300: 0x1F12,
+ 0x1F110300: 0x1F13,
+ 0x1F100301: 0x1F14,
+ 0x1F110301: 0x1F15,
+ 0x03950313: 0x1F18,
+ 0x03950314: 0x1F19,
+ 0x1F180300: 0x1F1A,
+ 0x1F190300: 0x1F1B,
+ 0x1F180301: 0x1F1C,
+ 0x1F190301: 0x1F1D,
+ 0x03B70313: 0x1F20,
+ 0x03B70314: 0x1F21,
+ 0x1F200300: 0x1F22,
+ 0x1F210300: 0x1F23,
+ 0x1F200301: 0x1F24,
+ 0x1F210301: 0x1F25,
+ 0x1F200342: 0x1F26,
+ 0x1F210342: 0x1F27,
+ 0x03970313: 0x1F28,
+ 0x03970314: 0x1F29,
+ 0x1F280300: 0x1F2A,
+ 0x1F290300: 0x1F2B,
+ 0x1F280301: 0x1F2C,
+ 0x1F290301: 0x1F2D,
+ 0x1F280342: 0x1F2E,
+ 0x1F290342: 0x1F2F,
+ 0x03B90313: 0x1F30,
+ 0x03B90314: 0x1F31,
+ 0x1F300300: 0x1F32,
+ 0x1F310300: 0x1F33,
+ 0x1F300301: 0x1F34,
+ 0x1F310301: 0x1F35,
+ 0x1F300342: 0x1F36,
+ 0x1F310342: 0x1F37,
+ 0x03990313: 0x1F38,
+ 0x03990314: 0x1F39,
+ 0x1F380300: 0x1F3A,
+ 0x1F390300: 0x1F3B,
+ 0x1F380301: 0x1F3C,
+ 0x1F390301: 0x1F3D,
+ 0x1F380342: 0x1F3E,
+ 0x1F390342: 0x1F3F,
+ 0x03BF0313: 0x1F40,
+ 0x03BF0314: 0x1F41,
+ 0x1F400300: 0x1F42,
+ 0x1F410300: 0x1F43,
+ 0x1F400301: 0x1F44,
+ 0x1F410301: 0x1F45,
+ 0x039F0313: 0x1F48,
+ 0x039F0314: 0x1F49,
+ 0x1F480300: 0x1F4A,
+ 0x1F490300: 0x1F4B,
+ 0x1F480301: 0x1F4C,
+ 0x1F490301: 0x1F4D,
+ 0x03C50313: 0x1F50,
+ 0x03C50314: 0x1F51,
+ 0x1F500300: 0x1F52,
+ 0x1F510300: 0x1F53,
+ 0x1F500301: 0x1F54,
+ 0x1F510301: 0x1F55,
+ 0x1F500342: 0x1F56,
+ 0x1F510342: 0x1F57,
+ 0x03A50314: 0x1F59,
+ 0x1F590300: 0x1F5B,
+ 0x1F590301: 0x1F5D,
+ 0x1F590342: 0x1F5F,
+ 0x03C90313: 0x1F60,
+ 0x03C90314: 0x1F61,
+ 0x1F600300: 0x1F62,
+ 0x1F610300: 0x1F63,
+ 0x1F600301: 0x1F64,
+ 0x1F610301: 0x1F65,
+ 0x1F600342: 0x1F66,
+ 0x1F610342: 0x1F67,
+ 0x03A90313: 0x1F68,
+ 0x03A90314: 0x1F69,
+ 0x1F680300: 0x1F6A,
+ 0x1F690300: 0x1F6B,
+ 0x1F680301: 0x1F6C,
+ 0x1F690301: 0x1F6D,
+ 0x1F680342: 0x1F6E,
+ 0x1F690342: 0x1F6F,
+ 0x03B10300: 0x1F70,
+ 0x03B50300: 0x1F72,
+ 0x03B70300: 0x1F74,
+ 0x03B90300: 0x1F76,
+ 0x03BF0300: 0x1F78,
+ 0x03C50300: 0x1F7A,
+ 0x03C90300: 0x1F7C,
+ 0x1F000345: 0x1F80,
+ 0x1F010345: 0x1F81,
+ 0x1F020345: 0x1F82,
+ 0x1F030345: 0x1F83,
+ 0x1F040345: 0x1F84,
+ 0x1F050345: 0x1F85,
+ 0x1F060345: 0x1F86,
+ 0x1F070345: 0x1F87,
+ 0x1F080345: 0x1F88,
+ 0x1F090345: 0x1F89,
+ 0x1F0A0345: 0x1F8A,
+ 0x1F0B0345: 0x1F8B,
+ 0x1F0C0345: 0x1F8C,
+ 0x1F0D0345: 0x1F8D,
+ 0x1F0E0345: 0x1F8E,
+ 0x1F0F0345: 0x1F8F,
+ 0x1F200345: 0x1F90,
+ 0x1F210345: 0x1F91,
+ 0x1F220345: 0x1F92,
+ 0x1F230345: 0x1F93,
+ 0x1F240345: 0x1F94,
+ 0x1F250345: 0x1F95,
+ 0x1F260345: 0x1F96,
+ 0x1F270345: 0x1F97,
+ 0x1F280345: 0x1F98,
+ 0x1F290345: 0x1F99,
+ 0x1F2A0345: 0x1F9A,
+ 0x1F2B0345: 0x1F9B,
+ 0x1F2C0345: 0x1F9C,
+ 0x1F2D0345: 0x1F9D,
+ 0x1F2E0345: 0x1F9E,
+ 0x1F2F0345: 0x1F9F,
+ 0x1F600345: 0x1FA0,
+ 0x1F610345: 0x1FA1,
+ 0x1F620345: 0x1FA2,
+ 0x1F630345: 0x1FA3,
+ 0x1F640345: 0x1FA4,
+ 0x1F650345: 0x1FA5,
+ 0x1F660345: 0x1FA6,
+ 0x1F670345: 0x1FA7,
+ 0x1F680345: 0x1FA8,
+ 0x1F690345: 0x1FA9,
+ 0x1F6A0345: 0x1FAA,
+ 0x1F6B0345: 0x1FAB,
+ 0x1F6C0345: 0x1FAC,
+ 0x1F6D0345: 0x1FAD,
+ 0x1F6E0345: 0x1FAE,
+ 0x1F6F0345: 0x1FAF,
+ 0x03B10306: 0x1FB0,
+ 0x03B10304: 0x1FB1,
+ 0x1F700345: 0x1FB2,
+ 0x03B10345: 0x1FB3,
+ 0x03AC0345: 0x1FB4,
+ 0x03B10342: 0x1FB6,
+ 0x1FB60345: 0x1FB7,
+ 0x03910306: 0x1FB8,
+ 0x03910304: 0x1FB9,
+ 0x03910300: 0x1FBA,
+ 0x03910345: 0x1FBC,
+ 0x00A80342: 0x1FC1,
+ 0x1F740345: 0x1FC2,
+ 0x03B70345: 0x1FC3,
+ 0x03AE0345: 0x1FC4,
+ 0x03B70342: 0x1FC6,
+ 0x1FC60345: 0x1FC7,
+ 0x03950300: 0x1FC8,
+ 0x03970300: 0x1FCA,
+ 0x03970345: 0x1FCC,
+ 0x1FBF0300: 0x1FCD,
+ 0x1FBF0301: 0x1FCE,
+ 0x1FBF0342: 0x1FCF,
+ 0x03B90306: 0x1FD0,
+ 0x03B90304: 0x1FD1,
+ 0x03CA0300: 0x1FD2,
+ 0x03B90342: 0x1FD6,
+ 0x03CA0342: 0x1FD7,
+ 0x03990306: 0x1FD8,
+ 0x03990304: 0x1FD9,
+ 0x03990300: 0x1FDA,
+ 0x1FFE0300: 0x1FDD,
+ 0x1FFE0301: 0x1FDE,
+ 0x1FFE0342: 0x1FDF,
+ 0x03C50306: 0x1FE0,
+ 0x03C50304: 0x1FE1,
+ 0x03CB0300: 0x1FE2,
+ 0x03C10313: 0x1FE4,
+ 0x03C10314: 0x1FE5,
+ 0x03C50342: 0x1FE6,
+ 0x03CB0342: 0x1FE7,
+ 0x03A50306: 0x1FE8,
+ 0x03A50304: 0x1FE9,
+ 0x03A50300: 0x1FEA,
+ 0x03A10314: 0x1FEC,
+ 0x00A80300: 0x1FED,
+ 0x1F7C0345: 0x1FF2,
+ 0x03C90345: 0x1FF3,
+ 0x03CE0345: 0x1FF4,
+ 0x03C90342: 0x1FF6,
+ 0x1FF60345: 0x1FF7,
+ 0x039F0300: 0x1FF8,
+ 0x03A90300: 0x1FFA,
+ 0x03A90345: 0x1FFC,
+ 0x21900338: 0x219A,
+ 0x21920338: 0x219B,
+ 0x21940338: 0x21AE,
+ 0x21D00338: 0x21CD,
+ 0x21D40338: 0x21CE,
+ 0x21D20338: 0x21CF,
+ 0x22030338: 0x2204,
+ 0x22080338: 0x2209,
+ 0x220B0338: 0x220C,
+ 0x22230338: 0x2224,
+ 0x22250338: 0x2226,
+ 0x223C0338: 0x2241,
+ 0x22430338: 0x2244,
+ 0x22450338: 0x2247,
+ 0x22480338: 0x2249,
+ 0x003D0338: 0x2260,
+ 0x22610338: 0x2262,
+ 0x224D0338: 0x226D,
+ 0x003C0338: 0x226E,
+ 0x003E0338: 0x226F,
+ 0x22640338: 0x2270,
+ 0x22650338: 0x2271,
+ 0x22720338: 0x2274,
+ 0x22730338: 0x2275,
+ 0x22760338: 0x2278,
+ 0x22770338: 0x2279,
+ 0x227A0338: 0x2280,
+ 0x227B0338: 0x2281,
+ 0x22820338: 0x2284,
+ 0x22830338: 0x2285,
+ 0x22860338: 0x2288,
+ 0x22870338: 0x2289,
+ 0x22A20338: 0x22AC,
+ 0x22A80338: 0x22AD,
+ 0x22A90338: 0x22AE,
+ 0x22AB0338: 0x22AF,
+ 0x227C0338: 0x22E0,
+ 0x227D0338: 0x22E1,
+ 0x22910338: 0x22E2,
+ 0x22920338: 0x22E3,
+ 0x22B20338: 0x22EA,
+ 0x22B30338: 0x22EB,
+ 0x22B40338: 0x22EC,
+ 0x22B50338: 0x22ED,
+ 0x304B3099: 0x304C,
+ 0x304D3099: 0x304E,
+ 0x304F3099: 0x3050,
+ 0x30513099: 0x3052,
+ 0x30533099: 0x3054,
+ 0x30553099: 0x3056,
+ 0x30573099: 0x3058,
+ 0x30593099: 0x305A,
+ 0x305B3099: 0x305C,
+ 0x305D3099: 0x305E,
+ 0x305F3099: 0x3060,
+ 0x30613099: 0x3062,
+ 0x30643099: 0x3065,
+ 0x30663099: 0x3067,
+ 0x30683099: 0x3069,
+ 0x306F3099: 0x3070,
+ 0x306F309A: 0x3071,
+ 0x30723099: 0x3073,
+ 0x3072309A: 0x3074,
+ 0x30753099: 0x3076,
+ 0x3075309A: 0x3077,
+ 0x30783099: 0x3079,
+ 0x3078309A: 0x307A,
+ 0x307B3099: 0x307C,
+ 0x307B309A: 0x307D,
+ 0x30463099: 0x3094,
+ 0x309D3099: 0x309E,
+ 0x30AB3099: 0x30AC,
+ 0x30AD3099: 0x30AE,
+ 0x30AF3099: 0x30B0,
+ 0x30B13099: 0x30B2,
+ 0x30B33099: 0x30B4,
+ 0x30B53099: 0x30B6,
+ 0x30B73099: 0x30B8,
+ 0x30B93099: 0x30BA,
+ 0x30BB3099: 0x30BC,
+ 0x30BD3099: 0x30BE,
+ 0x30BF3099: 0x30C0,
+ 0x30C13099: 0x30C2,
+ 0x30C43099: 0x30C5,
+ 0x30C63099: 0x30C7,
+ 0x30C83099: 0x30C9,
+ 0x30CF3099: 0x30D0,
+ 0x30CF309A: 0x30D1,
+ 0x30D23099: 0x30D3,
+ 0x30D2309A: 0x30D4,
+ 0x30D53099: 0x30D6,
+ 0x30D5309A: 0x30D7,
+ 0x30D83099: 0x30D9,
+ 0x30D8309A: 0x30DA,
+ 0x30DB3099: 0x30DC,
+ 0x30DB309A: 0x30DD,
+ 0x30A63099: 0x30F4,
+ 0x30EF3099: 0x30F7,
+ 0x30F03099: 0x30F8,
+ 0x30F13099: 0x30F9,
+ 0x30F23099: 0x30FA,
+ 0x30FD3099: 0x30FE,
+ 0x109910BA: 0x1109A,
+ 0x109B10BA: 0x1109C,
+ 0x10A510BA: 0x110AB,
+}
+
+// charInfoValues: 10944 entries, 21888 bytes
+// Block 2 is the null block.
+var charInfoValues = [10944]uint16{
+ // Block 0x0, offset 0x0
+ 0x003c: 0x8800, 0x003d: 0x8800, 0x003e: 0x8800,
+ // Block 0x1, offset 0x40
+ 0x0041: 0x8800, 0x0042: 0x8800, 0x0043: 0x8800, 0x0044: 0x8800, 0x0045: 0x8800,
+ 0x0046: 0x8800, 0x0047: 0x8800, 0x0048: 0x8800, 0x0049: 0x8800, 0x004a: 0x8800, 0x004b: 0x8800,
+ 0x004c: 0x8800, 0x004d: 0x8800, 0x004e: 0x8800, 0x004f: 0x8800, 0x0050: 0x8800,
+ 0x0052: 0x8800, 0x0053: 0x8800, 0x0054: 0x8800, 0x0055: 0x8800, 0x0056: 0x8800, 0x0057: 0x8800,
+ 0x0058: 0x8800, 0x0059: 0x8800, 0x005a: 0x8800,
+ 0x0061: 0x8800, 0x0062: 0x8800, 0x0063: 0x8800,
+ 0x0064: 0x8800, 0x0065: 0x8800, 0x0066: 0x8800, 0x0067: 0x8800, 0x0068: 0x8800, 0x0069: 0x8800,
+ 0x006a: 0x8800, 0x006b: 0x8800, 0x006c: 0x8800, 0x006d: 0x8800, 0x006e: 0x8800, 0x006f: 0x8800,
+ 0x0070: 0x8800, 0x0072: 0x8800, 0x0073: 0x8800, 0x0074: 0x8800, 0x0075: 0x8800,
+ 0x0076: 0x8800, 0x0077: 0x8800, 0x0078: 0x8800, 0x0079: 0x8800, 0x007a: 0x8800,
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x00e0: 0x3000,
+ 0x00e8: 0x3800,
+ 0x00ea: 0x3000, 0x00ef: 0x3000,
+ 0x00f2: 0x3000, 0x00f3: 0x3000, 0x00f4: 0x3000, 0x00f5: 0x3000,
+ 0x00f8: 0x3000, 0x00f9: 0x3000, 0x00fa: 0x3000,
+ 0x00fc: 0x3000, 0x00fd: 0x3000, 0x00fe: 0x3000,
+ // Block 0x4, offset 0x100
+ 0x0100: 0x1100, 0x0101: 0x1100, 0x0102: 0x9900, 0x0103: 0x1100, 0x0104: 0x9900, 0x0105: 0x9900,
+ 0x0106: 0x8800, 0x0107: 0x9900, 0x0108: 0x1100, 0x0109: 0x1100, 0x010a: 0x9900, 0x010b: 0x1100,
+ 0x010c: 0x1100, 0x010d: 0x1100, 0x010e: 0x1100, 0x010f: 0x9900, 0x0111: 0x1100,
+ 0x0112: 0x1100, 0x0113: 0x1100, 0x0114: 0x9900, 0x0115: 0x9900, 0x0116: 0x9900,
+ 0x0118: 0x8800, 0x0119: 0x1100, 0x011a: 0x1100, 0x011b: 0x1100, 0x011c: 0x9900, 0x011d: 0x1100,
+ 0x0120: 0x1100, 0x0121: 0x1100, 0x0122: 0x9900, 0x0123: 0x1100,
+ 0x0124: 0x9900, 0x0125: 0x9900, 0x0126: 0x8800, 0x0127: 0x9900, 0x0128: 0x1100, 0x0129: 0x1100,
+ 0x012a: 0x9900, 0x012b: 0x1100, 0x012c: 0x1100, 0x012d: 0x1100, 0x012e: 0x1100, 0x012f: 0x9900,
+ 0x0131: 0x1100, 0x0132: 0x1100, 0x0133: 0x1100, 0x0134: 0x9900, 0x0135: 0x9900,
+ 0x0136: 0x9900, 0x0138: 0x8800, 0x0139: 0x1100, 0x013a: 0x1100, 0x013b: 0x1100,
+ 0x013c: 0x9900, 0x013d: 0x1100, 0x013f: 0x1100,
+ // Block 0x5, offset 0x140
+ 0x0140: 0x1100, 0x0141: 0x1100, 0x0142: 0x9900, 0x0143: 0x9900, 0x0144: 0x1100, 0x0145: 0x1100,
+ 0x0146: 0x1100, 0x0147: 0x1100, 0x0148: 0x1100, 0x0149: 0x1100, 0x014a: 0x1100, 0x014b: 0x1100,
+ 0x014c: 0x1100, 0x014d: 0x1100, 0x014e: 0x1100, 0x014f: 0x1100,
+ 0x0152: 0x9900, 0x0153: 0x9900, 0x0154: 0x1100, 0x0155: 0x1100, 0x0156: 0x1100, 0x0157: 0x1100,
+ 0x0158: 0x1100, 0x0159: 0x1100, 0x015a: 0x1100, 0x015b: 0x1100, 0x015c: 0x1100, 0x015d: 0x1100,
+ 0x015e: 0x1100, 0x015f: 0x1100, 0x0160: 0x1100, 0x0161: 0x1100, 0x0162: 0x1100, 0x0163: 0x1100,
+ 0x0164: 0x1100, 0x0165: 0x1100, 0x0168: 0x1100, 0x0169: 0x1100,
+ 0x016a: 0x1100, 0x016b: 0x1100, 0x016c: 0x1100, 0x016d: 0x1100, 0x016e: 0x1100, 0x016f: 0x1100,
+ 0x0170: 0x1100, 0x0172: 0x3000, 0x0173: 0x3000, 0x0174: 0x1100, 0x0175: 0x1100,
+ 0x0176: 0x1100, 0x0177: 0x1100, 0x0179: 0x1100, 0x017a: 0x1100, 0x017b: 0x1100,
+ 0x017c: 0x1100, 0x017d: 0x1100, 0x017e: 0x1100, 0x017f: 0x3000,
+ // Block 0x6, offset 0x180
+ 0x0180: 0x3000, 0x0183: 0x1100, 0x0184: 0x1100, 0x0185: 0x1100,
+ 0x0186: 0x1100, 0x0187: 0x1100, 0x0188: 0x1100, 0x0189: 0x3000,
+ 0x018c: 0x9900, 0x018d: 0x9900, 0x018e: 0x1100, 0x018f: 0x1100, 0x0190: 0x1100, 0x0191: 0x1100,
+ 0x0194: 0x1100, 0x0195: 0x1100, 0x0196: 0x1100, 0x0197: 0x1100,
+ 0x0198: 0x1100, 0x0199: 0x1100, 0x019a: 0x9900, 0x019b: 0x9900, 0x019c: 0x1100, 0x019d: 0x1100,
+ 0x019e: 0x1100, 0x019f: 0x1100, 0x01a0: 0x9900, 0x01a1: 0x9900, 0x01a2: 0x1100, 0x01a3: 0x1100,
+ 0x01a4: 0x1100, 0x01a5: 0x1100, 0x01a8: 0x9900, 0x01a9: 0x9900,
+ 0x01aa: 0x9900, 0x01ab: 0x9900, 0x01ac: 0x1100, 0x01ad: 0x1100, 0x01ae: 0x1100, 0x01af: 0x1100,
+ 0x01b0: 0x1100, 0x01b1: 0x1100, 0x01b2: 0x1100, 0x01b3: 0x1100, 0x01b4: 0x1100, 0x01b5: 0x1100,
+ 0x01b6: 0x1100, 0x01b7: 0x1100, 0x01b8: 0x1100, 0x01b9: 0x1100, 0x01ba: 0x1100, 0x01bb: 0x1100,
+ 0x01bc: 0x1100, 0x01bd: 0x1100, 0x01be: 0x1100, 0x01bf: 0x3800,
+ // Block 0x7, offset 0x1c0
+ 0x01e0: 0x9900, 0x01e1: 0x9900,
+ 0x01ef: 0x9900,
+ 0x01f0: 0x9900,
+ 0x01f7: 0x8800,
+ // Block 0x8, offset 0x200
+ 0x0204: 0x3000, 0x0205: 0x3000,
+ 0x0206: 0x3000, 0x0207: 0x3000, 0x0208: 0x3000, 0x0209: 0x3000, 0x020a: 0x3000, 0x020b: 0x3000,
+ 0x020c: 0x3000, 0x020d: 0x1100, 0x020e: 0x1100, 0x020f: 0x1100, 0x0210: 0x1100, 0x0211: 0x1100,
+ 0x0212: 0x1100, 0x0213: 0x1100, 0x0214: 0x1100, 0x0215: 0x1100, 0x0216: 0x1100, 0x0217: 0x1100,
+ 0x0218: 0x1100, 0x0219: 0x1100, 0x021a: 0x1100, 0x021b: 0x1100, 0x021c: 0x1100,
+ 0x021e: 0x1100, 0x021f: 0x1100, 0x0220: 0x1100, 0x0221: 0x1100, 0x0222: 0x1100, 0x0223: 0x1100,
+ 0x0226: 0x1100, 0x0227: 0x1100, 0x0228: 0x1100, 0x0229: 0x1100,
+ 0x022a: 0x9900, 0x022b: 0x9900, 0x022c: 0x1100, 0x022d: 0x1100, 0x022e: 0x1100, 0x022f: 0x1100,
+ 0x0230: 0x1100, 0x0231: 0x3000, 0x0232: 0x3000, 0x0233: 0x3000, 0x0234: 0x1100, 0x0235: 0x1100,
+ 0x0238: 0x1100, 0x0239: 0x1100, 0x023a: 0x1100, 0x023b: 0x1100,
+ 0x023c: 0x1100, 0x023d: 0x1100, 0x023e: 0x1100, 0x023f: 0x1100,
+ // Block 0x9, offset 0x240
+ 0x0240: 0x1100, 0x0241: 0x1100, 0x0242: 0x1100, 0x0243: 0x1100, 0x0244: 0x1100, 0x0245: 0x1100,
+ 0x0246: 0x1100, 0x0247: 0x1100, 0x0248: 0x1100, 0x0249: 0x1100, 0x024a: 0x1100, 0x024b: 0x1100,
+ 0x024c: 0x1100, 0x024d: 0x1100, 0x024e: 0x1100, 0x024f: 0x1100, 0x0250: 0x1100, 0x0251: 0x1100,
+ 0x0252: 0x1100, 0x0253: 0x1100, 0x0254: 0x1100, 0x0255: 0x1100, 0x0256: 0x1100, 0x0257: 0x1100,
+ 0x0258: 0x1100, 0x0259: 0x1100, 0x025a: 0x1100, 0x025b: 0x1100,
+ 0x025e: 0x1100, 0x025f: 0x1100,
+ 0x0266: 0x9900, 0x0267: 0x9900, 0x0268: 0x9900, 0x0269: 0x9900,
+ 0x026a: 0x1100, 0x026b: 0x1100, 0x026c: 0x1100, 0x026d: 0x1100, 0x026e: 0x9900, 0x026f: 0x9900,
+ 0x0270: 0x1100, 0x0271: 0x1100, 0x0272: 0x1100, 0x0273: 0x1100,
+ // Block 0xa, offset 0x280
+ 0x0292: 0x8800,
+ 0x02b0: 0x3000, 0x02b1: 0x3000, 0x02b2: 0x3000, 0x02b3: 0x3000, 0x02b4: 0x3000, 0x02b5: 0x3000,
+ 0x02b6: 0x3000, 0x02b7: 0x3000, 0x02b8: 0x3000,
+ // Block 0xb, offset 0x2c0
+ 0x02d8: 0x3000, 0x02d9: 0x3000, 0x02da: 0x3000, 0x02db: 0x3000, 0x02dc: 0x3000, 0x02dd: 0x3000,
+ 0x02e0: 0x3000, 0x02e1: 0x3000, 0x02e2: 0x3000, 0x02e3: 0x3000,
+ 0x02e4: 0x3000,
+ // Block 0xc, offset 0x300
+ 0x0300: 0x66e6, 0x0301: 0x66e6, 0x0302: 0x66e6, 0x0303: 0x66e6, 0x0304: 0x66e6, 0x0305: 0x00e6,
+ 0x0306: 0x66e6, 0x0307: 0x66e6, 0x0308: 0x66e6, 0x0309: 0x66e6, 0x030a: 0x66e6, 0x030b: 0x66e6,
+ 0x030c: 0x66e6, 0x030d: 0x00e6, 0x030e: 0x00e6, 0x030f: 0x66e6, 0x0310: 0x00e6, 0x0311: 0x66e6,
+ 0x0312: 0x00e6, 0x0313: 0x66e6, 0x0314: 0x66e6, 0x0315: 0x00e8, 0x0316: 0x00dc, 0x0317: 0x00dc,
+ 0x0318: 0x00dc, 0x0319: 0x00dc, 0x031a: 0x00e8, 0x031b: 0x66d8, 0x031c: 0x00dc, 0x031d: 0x00dc,
+ 0x031e: 0x00dc, 0x031f: 0x00dc, 0x0320: 0x00dc, 0x0321: 0x00ca, 0x0322: 0x00ca, 0x0323: 0x66dc,
+ 0x0324: 0x66dc, 0x0325: 0x66dc, 0x0326: 0x66dc, 0x0327: 0x66ca, 0x0328: 0x66ca, 0x0329: 0x00dc,
+ 0x032a: 0x00dc, 0x032b: 0x00dc, 0x032c: 0x00dc, 0x032d: 0x66dc, 0x032e: 0x66dc, 0x032f: 0x00dc,
+ 0x0330: 0x66dc, 0x0331: 0x66dc, 0x0332: 0x00dc, 0x0333: 0x00dc, 0x0334: 0x0001, 0x0335: 0x0001,
+ 0x0336: 0x0001, 0x0337: 0x0001, 0x0338: 0x6601, 0x0339: 0x00dc, 0x033a: 0x00dc, 0x033b: 0x00dc,
+ 0x033c: 0x00dc, 0x033d: 0x00e6, 0x033e: 0x00e6, 0x033f: 0x00e6,
+ // Block 0xd, offset 0x340
+ 0x0340: 0x33e6, 0x0341: 0x33e6, 0x0342: 0x66e6, 0x0343: 0x33e6, 0x0344: 0x33e6, 0x0345: 0x66f0,
+ 0x0346: 0x00e6, 0x0347: 0x00dc, 0x0348: 0x00dc, 0x0349: 0x00dc, 0x034a: 0x00e6, 0x034b: 0x00e6,
+ 0x034c: 0x00e6, 0x034d: 0x00dc, 0x034e: 0x00dc, 0x0350: 0x00e6, 0x0351: 0x00e6,
+ 0x0352: 0x00e6, 0x0353: 0x00dc, 0x0354: 0x00dc, 0x0355: 0x00dc, 0x0356: 0x00dc, 0x0357: 0x00e6,
+ 0x0358: 0x00e8, 0x0359: 0x00dc, 0x035a: 0x00dc, 0x035b: 0x00e6, 0x035c: 0x00e9, 0x035d: 0x00ea,
+ 0x035e: 0x00ea, 0x035f: 0x00e9, 0x0360: 0x00ea, 0x0361: 0x00ea, 0x0362: 0x00e9, 0x0363: 0x00e6,
+ 0x0364: 0x00e6, 0x0365: 0x00e6, 0x0366: 0x00e6, 0x0367: 0x00e6, 0x0368: 0x00e6, 0x0369: 0x00e6,
+ 0x036a: 0x00e6, 0x036b: 0x00e6, 0x036c: 0x00e6, 0x036d: 0x00e6, 0x036e: 0x00e6, 0x036f: 0x00e6,
+ 0x0374: 0x3300,
+ 0x037a: 0x3000,
+ 0x037e: 0x3300,
+ // Block 0xe, offset 0x380
+ 0x0384: 0x3000, 0x0385: 0x3100,
+ 0x0386: 0x1100, 0x0387: 0x3300, 0x0388: 0x1100, 0x0389: 0x1100, 0x038a: 0x1100,
+ 0x038c: 0x1100, 0x038e: 0x1100, 0x038f: 0x1100, 0x0390: 0x1100, 0x0391: 0x8800,
+ 0x0395: 0x8800, 0x0397: 0x8800,
+ 0x0399: 0x8800,
+ 0x039f: 0x8800, 0x03a1: 0x8800,
+ 0x03a5: 0x8800, 0x03a9: 0x8800,
+ 0x03aa: 0x1100, 0x03ab: 0x1100, 0x03ac: 0x9900, 0x03ad: 0x1100, 0x03ae: 0x9900, 0x03af: 0x1100,
+ 0x03b0: 0x1100, 0x03b1: 0x8800, 0x03b5: 0x8800,
+ 0x03b7: 0x8800, 0x03b9: 0x8800,
+ 0x03bf: 0x8800,
+ // Block 0xf, offset 0x3c0
+ 0x03c1: 0x8800, 0x03c5: 0x8800,
+ 0x03c9: 0x8800, 0x03ca: 0x9900, 0x03cb: 0x9900,
+ 0x03cc: 0x1100, 0x03cd: 0x1100, 0x03ce: 0x9900, 0x03d0: 0x3000, 0x03d1: 0x3000,
+ 0x03d2: 0x3800, 0x03d3: 0x3100, 0x03d4: 0x3100, 0x03d5: 0x3000, 0x03d6: 0x3000,
+ 0x03f0: 0x3000, 0x03f1: 0x3000, 0x03f2: 0x3000, 0x03f4: 0x3000, 0x03f5: 0x3000,
+ 0x03f9: 0x3000,
+ // Block 0x10, offset 0x400
+ 0x0400: 0x1100, 0x0401: 0x1100, 0x0403: 0x1100,
+ 0x0406: 0x8800, 0x0407: 0x1100,
+ 0x040c: 0x1100, 0x040d: 0x1100, 0x040e: 0x1100, 0x0410: 0x8800,
+ 0x0413: 0x8800, 0x0415: 0x8800, 0x0416: 0x8800, 0x0417: 0x8800,
+ 0x0418: 0x8800, 0x0419: 0x1100, 0x041a: 0x8800,
+ 0x041e: 0x8800, 0x0423: 0x8800,
+ 0x0427: 0x8800,
+ 0x042b: 0x8800, 0x042d: 0x8800,
+ 0x0430: 0x8800, 0x0433: 0x8800, 0x0435: 0x8800,
+ 0x0436: 0x8800, 0x0437: 0x8800, 0x0438: 0x8800, 0x0439: 0x1100, 0x043a: 0x8800,
+ 0x043e: 0x8800,
+ // Block 0x11, offset 0x440
+ 0x0443: 0x8800,
+ 0x0447: 0x8800, 0x044b: 0x8800,
+ 0x044d: 0x8800, 0x0450: 0x1100, 0x0451: 0x1100,
+ 0x0453: 0x1100, 0x0456: 0x8800, 0x0457: 0x1100,
+ 0x045c: 0x1100, 0x045d: 0x1100,
+ 0x045e: 0x1100,
+ 0x0474: 0x8800, 0x0475: 0x8800,
+ 0x0476: 0x1100, 0x0477: 0x1100,
+ // Block 0x12, offset 0x480
+ 0x0483: 0x00e6, 0x0484: 0x00e6, 0x0485: 0x00e6,
+ 0x0486: 0x00e6, 0x0487: 0x00e6,
+ // Block 0x13, offset 0x4c0
+ 0x04c1: 0x1100, 0x04c2: 0x1100,
+ 0x04d0: 0x1100, 0x04d1: 0x1100,
+ 0x04d2: 0x1100, 0x04d3: 0x1100, 0x04d6: 0x1100, 0x04d7: 0x1100,
+ 0x04d8: 0x8800, 0x04d9: 0x8800, 0x04da: 0x1100, 0x04db: 0x1100, 0x04dc: 0x1100, 0x04dd: 0x1100,
+ 0x04de: 0x1100, 0x04df: 0x1100, 0x04e2: 0x1100, 0x04e3: 0x1100,
+ 0x04e4: 0x1100, 0x04e5: 0x1100, 0x04e6: 0x1100, 0x04e7: 0x1100, 0x04e8: 0x8800, 0x04e9: 0x8800,
+ 0x04ea: 0x1100, 0x04eb: 0x1100, 0x04ec: 0x1100, 0x04ed: 0x1100, 0x04ee: 0x1100, 0x04ef: 0x1100,
+ 0x04f0: 0x1100, 0x04f1: 0x1100, 0x04f2: 0x1100, 0x04f3: 0x1100, 0x04f4: 0x1100, 0x04f5: 0x1100,
+ 0x04f8: 0x1100, 0x04f9: 0x1100,
+ // Block 0x14, offset 0x500
+ 0x0507: 0x3000,
+ 0x0511: 0x00dc,
+ 0x0512: 0x00e6, 0x0513: 0x00e6, 0x0514: 0x00e6, 0x0515: 0x00e6, 0x0516: 0x00dc, 0x0517: 0x00e6,
+ 0x0518: 0x00e6, 0x0519: 0x00e6, 0x051a: 0x00de, 0x051b: 0x00dc, 0x051c: 0x00e6, 0x051d: 0x00e6,
+ 0x051e: 0x00e6, 0x051f: 0x00e6, 0x0520: 0x00e6, 0x0521: 0x00e6, 0x0522: 0x00dc, 0x0523: 0x00dc,
+ 0x0524: 0x00dc, 0x0525: 0x00dc, 0x0526: 0x00dc, 0x0527: 0x00dc, 0x0528: 0x00e6, 0x0529: 0x00e6,
+ 0x052a: 0x00dc, 0x052b: 0x00e6, 0x052c: 0x00e6, 0x052d: 0x00de, 0x052e: 0x00e4, 0x052f: 0x00e6,
+ 0x0530: 0x000a, 0x0531: 0x000b, 0x0532: 0x000c, 0x0533: 0x000d, 0x0534: 0x000e, 0x0535: 0x000f,
+ 0x0536: 0x0010, 0x0537: 0x0011, 0x0538: 0x0012, 0x0539: 0x0013, 0x053a: 0x0013, 0x053b: 0x0014,
+ 0x053c: 0x0015, 0x053d: 0x0016, 0x053f: 0x0017,
+ // Block 0x15, offset 0x540
+ 0x0541: 0x0018, 0x0542: 0x0019, 0x0544: 0x00e6, 0x0545: 0x00dc,
+ 0x0547: 0x0012,
+ // Block 0x16, offset 0x580
+ 0x0590: 0x00e6, 0x0591: 0x00e6,
+ 0x0592: 0x00e6, 0x0593: 0x00e6, 0x0594: 0x00e6, 0x0595: 0x00e6, 0x0596: 0x00e6, 0x0597: 0x00e6,
+ 0x0598: 0x001e, 0x0599: 0x001f, 0x059a: 0x0020,
+ 0x05a2: 0x1100, 0x05a3: 0x1100,
+ 0x05a4: 0x1100, 0x05a5: 0x1100, 0x05a6: 0x1100, 0x05a7: 0x8800,
+ // Block 0x17, offset 0x5c0
+ 0x05c8: 0x8800, 0x05ca: 0x8800, 0x05cb: 0x001b,
+ 0x05cc: 0x001c, 0x05cd: 0x001d, 0x05ce: 0x001e, 0x05cf: 0x001f, 0x05d0: 0x0020, 0x05d1: 0x0021,
+ 0x05d2: 0x0022, 0x05d3: 0x66e6, 0x05d4: 0x66e6, 0x05d5: 0x66dc, 0x05d6: 0x00dc, 0x05d7: 0x00e6,
+ 0x05d8: 0x00e6, 0x05d9: 0x00e6, 0x05da: 0x00e6, 0x05db: 0x00e6, 0x05dc: 0x00dc, 0x05dd: 0x00e6,
+ 0x05de: 0x00e6, 0x05df: 0x00dc,
+ 0x05f0: 0x0023, 0x05f5: 0x3000,
+ 0x05f6: 0x3000, 0x05f7: 0x3000, 0x05f8: 0x3000,
+ // Block 0x18, offset 0x600
+ 0x0600: 0x1100, 0x0601: 0x8800, 0x0602: 0x1100,
+ 0x0612: 0x8800, 0x0613: 0x1100, 0x0615: 0x8800, 0x0616: 0x00e6, 0x0617: 0x00e6,
+ 0x0618: 0x00e6, 0x0619: 0x00e6, 0x061a: 0x00e6, 0x061b: 0x00e6, 0x061c: 0x00e6,
+ 0x061f: 0x00e6, 0x0620: 0x00e6, 0x0621: 0x00e6, 0x0622: 0x00e6, 0x0623: 0x00dc,
+ 0x0624: 0x00e6, 0x0627: 0x00e6, 0x0628: 0x00e6,
+ 0x062a: 0x00dc, 0x062b: 0x00e6, 0x062c: 0x00e6, 0x062d: 0x00dc,
+ // Block 0x19, offset 0x640
+ 0x0651: 0x0024,
+ 0x0670: 0x00e6, 0x0671: 0x00dc, 0x0672: 0x00e6, 0x0673: 0x00e6, 0x0674: 0x00dc, 0x0675: 0x00e6,
+ 0x0676: 0x00e6, 0x0677: 0x00dc, 0x0678: 0x00dc, 0x0679: 0x00dc, 0x067a: 0x00e6, 0x067b: 0x00dc,
+ 0x067c: 0x00dc, 0x067d: 0x00e6, 0x067e: 0x00dc, 0x067f: 0x00e6,
+ // Block 0x1a, offset 0x680
+ 0x0680: 0x00e6, 0x0681: 0x00e6, 0x0682: 0x00dc, 0x0683: 0x00e6, 0x0684: 0x00dc, 0x0685: 0x00e6,
+ 0x0686: 0x00dc, 0x0687: 0x00e6, 0x0688: 0x00dc, 0x0689: 0x00e6, 0x068a: 0x00e6,
+ // Block 0x1b, offset 0x6c0
+ 0x06eb: 0x00e6, 0x06ec: 0x00e6, 0x06ed: 0x00e6, 0x06ee: 0x00e6, 0x06ef: 0x00e6,
+ 0x06f0: 0x00e6, 0x06f1: 0x00e6, 0x06f2: 0x00dc, 0x06f3: 0x00e6,
+ // Block 0x1c, offset 0x700
+ 0x0716: 0x00e6, 0x0717: 0x00e6,
+ 0x0718: 0x00e6, 0x0719: 0x00e6, 0x071b: 0x00e6, 0x071c: 0x00e6, 0x071d: 0x00e6,
+ 0x071e: 0x00e6, 0x071f: 0x00e6, 0x0720: 0x00e6, 0x0721: 0x00e6, 0x0722: 0x00e6, 0x0723: 0x00e6,
+ 0x0725: 0x00e6, 0x0726: 0x00e6, 0x0727: 0x00e6, 0x0729: 0x00e6,
+ 0x072a: 0x00e6, 0x072b: 0x00e6, 0x072c: 0x00e6, 0x072d: 0x00e6,
+ // Block 0x1d, offset 0x740
+ 0x0759: 0x00dc, 0x075a: 0x00dc, 0x075b: 0x00dc,
+ // Block 0x1e, offset 0x780
+ 0x07a8: 0x8800, 0x07a9: 0x1100,
+ 0x07b0: 0x8800, 0x07b1: 0x1100, 0x07b3: 0x8800, 0x07b4: 0x1100,
+ 0x07bc: 0x6607,
+ // Block 0x1f, offset 0x7c0
+ 0x07cd: 0x0009, 0x07d1: 0x00e6,
+ 0x07d2: 0x00dc, 0x07d3: 0x00e6, 0x07d4: 0x00e6,
+ 0x07d8: 0x3300, 0x07d9: 0x3300, 0x07da: 0x3300, 0x07db: 0x3300, 0x07dc: 0x3300, 0x07dd: 0x3300,
+ 0x07de: 0x3300, 0x07df: 0x3300,
+ // Block 0x20, offset 0x800
+ 0x083c: 0x0007, 0x083e: 0x6600,
+ // Block 0x21, offset 0x840
+ 0x0847: 0x8800, 0x084b: 0x1100,
+ 0x084c: 0x1100, 0x084d: 0x0009,
+ 0x0857: 0x6600,
+ 0x085c: 0x3300, 0x085d: 0x3300,
+ 0x085f: 0x3300,
+ // Block 0x22, offset 0x880
+ 0x08b3: 0x3300,
+ 0x08b6: 0x3300,
+ 0x08bc: 0x0007,
+ // Block 0x23, offset 0x8c0
+ 0x08cd: 0x0009,
+ 0x08d9: 0x3300, 0x08da: 0x3300, 0x08db: 0x3300,
+ 0x08de: 0x3300,
+ // Block 0x24, offset 0x900
+ 0x093c: 0x0007,
+ // Block 0x25, offset 0x940
+ 0x094d: 0x0009,
+ // Block 0x26, offset 0x980
+ 0x0987: 0x8800, 0x0988: 0x1100, 0x098b: 0x1100,
+ 0x098c: 0x1100, 0x098d: 0x0009,
+ 0x0996: 0x6600, 0x0997: 0x6600,
+ 0x099c: 0x3300, 0x099d: 0x3300,
+ // Block 0x27, offset 0x9c0
+ 0x09d2: 0x8800, 0x09d4: 0x1100,
+ 0x09fe: 0x6600,
+ // Block 0x28, offset 0xa00
+ 0x0a06: 0x8800, 0x0a07: 0x8800, 0x0a0a: 0x1100, 0x0a0b: 0x1100,
+ 0x0a0c: 0x1100, 0x0a0d: 0x0009,
+ 0x0a17: 0x6600,
+ // Block 0x29, offset 0xa40
+ 0x0a46: 0x8800, 0x0a48: 0x1100,
+ 0x0a4d: 0x0009,
+ 0x0a55: 0x0054, 0x0a56: 0x665b,
+ // Block 0x2a, offset 0xa80
+ 0x0abc: 0x0007, 0x0abf: 0x8800,
+ // Block 0x2b, offset 0xac0
+ 0x0ac0: 0x1100, 0x0ac2: 0x6600,
+ 0x0ac6: 0x8800, 0x0ac7: 0x1100, 0x0ac8: 0x1100, 0x0aca: 0x9900, 0x0acb: 0x1100,
+ 0x0acd: 0x0009,
+ 0x0ad5: 0x6600, 0x0ad6: 0x6600,
+ // Block 0x2c, offset 0xb00
+ 0x0b3e: 0x6600,
+ // Block 0x2d, offset 0xb40
+ 0x0b4a: 0x6609,
+ 0x0b4f: 0x6600,
+ 0x0b59: 0x8800, 0x0b5a: 0x1100, 0x0b5c: 0x9900, 0x0b5d: 0x1100,
+ 0x0b5e: 0x1100, 0x0b5f: 0x6600,
+ // Block 0x2e, offset 0xb80
+ 0x0bb3: 0x3000,
+ 0x0bb8: 0x0067, 0x0bb9: 0x0067, 0x0bba: 0x0009,
+ // Block 0x2f, offset 0xbc0
+ 0x0bc8: 0x006b, 0x0bc9: 0x006b, 0x0bca: 0x006b, 0x0bcb: 0x006b,
+ // Block 0x30, offset 0xc00
+ 0x0c33: 0x3000,
+ 0x0c38: 0x0076, 0x0c39: 0x0076,
+ // Block 0x31, offset 0xc40
+ 0x0c48: 0x007a, 0x0c49: 0x007a, 0x0c4a: 0x007a, 0x0c4b: 0x007a,
+ 0x0c5c: 0x3000, 0x0c5d: 0x3000,
+ // Block 0x32, offset 0xc80
+ 0x0c8c: 0x3000,
+ 0x0c98: 0x00dc, 0x0c99: 0x00dc,
+ 0x0cb5: 0x00dc,
+ 0x0cb7: 0x00dc, 0x0cb9: 0x00d8,
+ // Block 0x33, offset 0xcc0
+ 0x0cc3: 0x3300,
+ 0x0ccd: 0x3300,
+ 0x0cd2: 0x3300, 0x0cd7: 0x3300,
+ 0x0cdc: 0x3300,
+ 0x0ce9: 0x3300,
+ 0x0cf1: 0x0081, 0x0cf2: 0x0082, 0x0cf3: 0x3300, 0x0cf4: 0x0084, 0x0cf5: 0x3300,
+ 0x0cf6: 0x3300, 0x0cf7: 0x3000, 0x0cf8: 0x3300, 0x0cf9: 0x3000, 0x0cfa: 0x0082, 0x0cfb: 0x0082,
+ 0x0cfc: 0x0082, 0x0cfd: 0x0082,
+ // Block 0x34, offset 0xd00
+ 0x0d00: 0x0082, 0x0d01: 0x3300, 0x0d02: 0x00e6, 0x0d03: 0x00e6, 0x0d04: 0x0009,
+ 0x0d06: 0x00e6, 0x0d07: 0x00e6,
+ 0x0d13: 0x3300,
+ 0x0d1d: 0x3300,
+ 0x0d22: 0x3300,
+ 0x0d27: 0x3300,
+ 0x0d2c: 0x3300,
+ 0x0d39: 0x3300,
+ // Block 0x35, offset 0xd40
+ 0x0d46: 0x00dc,
+ // Block 0x36, offset 0xd80
+ 0x0da5: 0x8800, 0x0da6: 0x1100,
+ 0x0dae: 0x6600,
+ 0x0db7: 0x0007, 0x0db9: 0x0009, 0x0dba: 0x0009,
+ // Block 0x37, offset 0xdc0
+ 0x0dcd: 0x00dc,
+ // Block 0x38, offset 0xe00
+ 0x0e3c: 0x3000,
+ // Block 0x39, offset 0xe40
+ 0x0e61: 0x6600, 0x0e62: 0x6600, 0x0e63: 0x6600,
+ 0x0e64: 0x6600, 0x0e65: 0x6600, 0x0e66: 0x6600, 0x0e67: 0x6600, 0x0e68: 0x6600, 0x0e69: 0x6600,
+ 0x0e6a: 0x6600, 0x0e6b: 0x6600, 0x0e6c: 0x6600, 0x0e6d: 0x6600, 0x0e6e: 0x6600, 0x0e6f: 0x6600,
+ 0x0e70: 0x6600, 0x0e71: 0x6600, 0x0e72: 0x6600, 0x0e73: 0x6600, 0x0e74: 0x6600, 0x0e75: 0x6600,
+ // Block 0x3a, offset 0xe80
+ 0x0ea8: 0x6600, 0x0ea9: 0x6600,
+ 0x0eaa: 0x6600, 0x0eab: 0x6600, 0x0eac: 0x6600, 0x0ead: 0x6600, 0x0eae: 0x6600, 0x0eaf: 0x6600,
+ 0x0eb0: 0x6600, 0x0eb1: 0x6600, 0x0eb2: 0x6600, 0x0eb3: 0x6600, 0x0eb4: 0x6600, 0x0eb5: 0x6600,
+ 0x0eb6: 0x6600, 0x0eb7: 0x6600, 0x0eb8: 0x6600, 0x0eb9: 0x6600, 0x0eba: 0x6600, 0x0ebb: 0x6600,
+ 0x0ebc: 0x6600, 0x0ebd: 0x6600, 0x0ebe: 0x6600, 0x0ebf: 0x6600,
+ // Block 0x3b, offset 0xec0
+ 0x0ec0: 0x6600, 0x0ec1: 0x6600, 0x0ec2: 0x6600,
+ // Block 0x3c, offset 0xf00
+ 0x0f1d: 0x00e6,
+ 0x0f1e: 0x00e6, 0x0f1f: 0x00e6,
+ // Block 0x3d, offset 0xf40
+ 0x0f54: 0x0009,
+ 0x0f74: 0x0009,
+ // Block 0x3e, offset 0xf80
+ 0x0f92: 0x0009,
+ 0x0f9d: 0x00e6,
+ // Block 0x3f, offset 0xfc0
+ 0x0fe9: 0x00e4,
+ // Block 0x40, offset 0x1000
+ 0x1039: 0x00de, 0x103a: 0x00e6, 0x103b: 0x00dc,
+ // Block 0x41, offset 0x1040
+ 0x1057: 0x00e6,
+ 0x1058: 0x00dc,
+ // Block 0x42, offset 0x1080
+ 0x10a0: 0x0009,
+ 0x10b5: 0x00e6,
+ 0x10b6: 0x00e6, 0x10b7: 0x00e6, 0x10b8: 0x00e6, 0x10b9: 0x00e6, 0x10ba: 0x00e6, 0x10bb: 0x00e6,
+ 0x10bc: 0x00e6, 0x10bf: 0x00dc,
+ // Block 0x43, offset 0x10c0
+ 0x10c5: 0x8800,
+ 0x10c6: 0x1100, 0x10c7: 0x8800, 0x10c8: 0x1100, 0x10c9: 0x8800, 0x10ca: 0x1100, 0x10cb: 0x8800,
+ 0x10cc: 0x1100, 0x10cd: 0x8800, 0x10ce: 0x1100, 0x10d1: 0x8800,
+ 0x10d2: 0x1100,
+ 0x10f4: 0x0007, 0x10f5: 0x6600,
+ 0x10fa: 0x8800, 0x10fb: 0x1100,
+ 0x10fc: 0x8800, 0x10fd: 0x1100, 0x10fe: 0x8800, 0x10ff: 0x8800,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x1100, 0x1101: 0x1100, 0x1102: 0x8800, 0x1103: 0x1100, 0x1104: 0x0009,
+ 0x112b: 0x00e6, 0x112c: 0x00dc, 0x112d: 0x00e6, 0x112e: 0x00e6, 0x112f: 0x00e6,
+ 0x1130: 0x00e6, 0x1131: 0x00e6, 0x1132: 0x00e6, 0x1133: 0x00e6,
+ // Block 0x45, offset 0x1140
+ 0x116a: 0x0009,
+ // Block 0x46, offset 0x1180
+ 0x11a6: 0x0007,
+ 0x11b2: 0x0009, 0x11b3: 0x0009,
+ // Block 0x47, offset 0x11c0
+ 0x11f7: 0x0007,
+ // Block 0x48, offset 0x1200
+ 0x1210: 0x00e6, 0x1211: 0x00e6,
+ 0x1212: 0x00e6, 0x1214: 0x0001, 0x1215: 0x00dc, 0x1216: 0x00dc, 0x1217: 0x00dc,
+ 0x1218: 0x00dc, 0x1219: 0x00dc, 0x121a: 0x00e6, 0x121b: 0x00e6, 0x121c: 0x00dc, 0x121d: 0x00dc,
+ 0x121e: 0x00dc, 0x121f: 0x00dc, 0x1220: 0x00e6, 0x1222: 0x0001, 0x1223: 0x0001,
+ 0x1224: 0x0001, 0x1225: 0x0001, 0x1226: 0x0001, 0x1227: 0x0001, 0x1228: 0x0001,
+ 0x122d: 0x00dc,
+ // Block 0x49, offset 0x1240
+ 0x126c: 0x3000, 0x126d: 0x3000, 0x126e: 0x3000,
+ 0x1270: 0x3000, 0x1271: 0x3000, 0x1272: 0x3000, 0x1273: 0x3000, 0x1274: 0x3000, 0x1275: 0x3000,
+ 0x1276: 0x3000, 0x1277: 0x3000, 0x1278: 0x3000, 0x1279: 0x3000, 0x127a: 0x3000,
+ 0x127c: 0x3000, 0x127d: 0x3000, 0x127e: 0x3000, 0x127f: 0x3000,
+ // Block 0x4a, offset 0x1280
+ 0x1280: 0x3000, 0x1281: 0x3000, 0x1282: 0x3000, 0x1283: 0x3000, 0x1284: 0x3000, 0x1285: 0x3000,
+ 0x1286: 0x3000, 0x1287: 0x3000, 0x1288: 0x3000, 0x1289: 0x3000, 0x128a: 0x3000, 0x128b: 0x3000,
+ 0x128c: 0x3000, 0x128d: 0x3000, 0x128f: 0x3000, 0x1290: 0x3000, 0x1291: 0x3000,
+ 0x1292: 0x3000, 0x1293: 0x3000, 0x1294: 0x3000, 0x1295: 0x3000, 0x1296: 0x3000, 0x1297: 0x3000,
+ 0x1298: 0x3000, 0x1299: 0x3000, 0x129a: 0x3000, 0x129b: 0x3000, 0x129c: 0x3000, 0x129d: 0x3000,
+ 0x129e: 0x3000, 0x129f: 0x3000, 0x12a0: 0x3000, 0x12a1: 0x3000, 0x12a2: 0x3000, 0x12a3: 0x3000,
+ 0x12a4: 0x3000, 0x12a5: 0x3000, 0x12a6: 0x3000, 0x12a7: 0x3000, 0x12a8: 0x3000, 0x12a9: 0x3000,
+ 0x12aa: 0x3000,
+ 0x12b8: 0x3000,
+ // Block 0x4b, offset 0x12c0
+ 0x12db: 0x3000, 0x12dc: 0x3000, 0x12dd: 0x3000,
+ 0x12de: 0x3000, 0x12df: 0x3000, 0x12e0: 0x3000, 0x12e1: 0x3000, 0x12e2: 0x3000, 0x12e3: 0x3000,
+ 0x12e4: 0x3000, 0x12e5: 0x3000, 0x12e6: 0x3000, 0x12e7: 0x3000, 0x12e8: 0x3000, 0x12e9: 0x3000,
+ 0x12ea: 0x3000, 0x12eb: 0x3000, 0x12ec: 0x3000, 0x12ed: 0x3000, 0x12ee: 0x3000, 0x12ef: 0x3000,
+ 0x12f0: 0x3000, 0x12f1: 0x3000, 0x12f2: 0x3000, 0x12f3: 0x3000, 0x12f4: 0x3000, 0x12f5: 0x3000,
+ 0x12f6: 0x3000, 0x12f7: 0x3000, 0x12f8: 0x3000, 0x12f9: 0x3000, 0x12fa: 0x3000, 0x12fb: 0x3000,
+ 0x12fc: 0x3000, 0x12fd: 0x3000, 0x12fe: 0x3000, 0x12ff: 0x3000,
+ // Block 0x4c, offset 0x1300
+ 0x1300: 0x00e6, 0x1301: 0x00e6, 0x1302: 0x00dc, 0x1303: 0x00e6, 0x1304: 0x00e6, 0x1305: 0x00e6,
+ 0x1306: 0x00e6, 0x1307: 0x00e6, 0x1308: 0x00e6, 0x1309: 0x00e6, 0x130a: 0x00dc, 0x130b: 0x00e6,
+ 0x130c: 0x00e6, 0x130d: 0x00ea, 0x130e: 0x00d6, 0x130f: 0x00dc, 0x1310: 0x00ca, 0x1311: 0x00e6,
+ 0x1312: 0x00e6, 0x1313: 0x00e6, 0x1314: 0x00e6, 0x1315: 0x00e6, 0x1316: 0x00e6, 0x1317: 0x00e6,
+ 0x1318: 0x00e6, 0x1319: 0x00e6, 0x131a: 0x00e6, 0x131b: 0x00e6, 0x131c: 0x00e6, 0x131d: 0x00e6,
+ 0x131e: 0x00e6, 0x131f: 0x00e6, 0x1320: 0x00e6, 0x1321: 0x00e6, 0x1322: 0x00e6, 0x1323: 0x00e6,
+ 0x1324: 0x00e6, 0x1325: 0x00e6, 0x1326: 0x00e6,
+ 0x133c: 0x00e9, 0x133d: 0x00dc, 0x133e: 0x00e6, 0x133f: 0x00dc,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x1100, 0x1341: 0x1100, 0x1342: 0x1100, 0x1343: 0x1100, 0x1344: 0x1100, 0x1345: 0x1100,
+ 0x1346: 0x1100, 0x1347: 0x1100, 0x1348: 0x1100, 0x1349: 0x1100, 0x134a: 0x1100, 0x134b: 0x1100,
+ 0x134c: 0x1100, 0x134d: 0x1100, 0x134e: 0x1100, 0x134f: 0x1100, 0x1350: 0x1100, 0x1351: 0x1100,
+ 0x1352: 0x1100, 0x1353: 0x1100, 0x1354: 0x1100, 0x1355: 0x1100, 0x1356: 0x1100, 0x1357: 0x1100,
+ 0x1358: 0x1100, 0x1359: 0x1100, 0x135a: 0x1100, 0x135b: 0x1100, 0x135c: 0x1100, 0x135d: 0x1100,
+ 0x135e: 0x1100, 0x135f: 0x1100, 0x1360: 0x1100, 0x1361: 0x1100, 0x1362: 0x1100, 0x1363: 0x1100,
+ 0x1364: 0x1100, 0x1365: 0x1100, 0x1366: 0x1100, 0x1367: 0x1100, 0x1368: 0x1100, 0x1369: 0x1100,
+ 0x136a: 0x1100, 0x136b: 0x1100, 0x136c: 0x1100, 0x136d: 0x1100, 0x136e: 0x1100, 0x136f: 0x1100,
+ 0x1370: 0x1100, 0x1371: 0x1100, 0x1372: 0x1100, 0x1373: 0x1100, 0x1374: 0x1100, 0x1375: 0x1100,
+ 0x1376: 0x9900, 0x1377: 0x9900, 0x1378: 0x1100, 0x1379: 0x1100, 0x137a: 0x1100, 0x137b: 0x1100,
+ 0x137c: 0x1100, 0x137d: 0x1100, 0x137e: 0x1100, 0x137f: 0x1100,
+ // Block 0x4e, offset 0x1380
+ 0x1380: 0x1100, 0x1381: 0x1100, 0x1382: 0x1100, 0x1383: 0x1100, 0x1384: 0x1100, 0x1385: 0x1100,
+ 0x1386: 0x1100, 0x1387: 0x1100, 0x1388: 0x1100, 0x1389: 0x1100, 0x138a: 0x1100, 0x138b: 0x1100,
+ 0x138c: 0x1100, 0x138d: 0x1100, 0x138e: 0x1100, 0x138f: 0x1100, 0x1390: 0x1100, 0x1391: 0x1100,
+ 0x1392: 0x1100, 0x1393: 0x1100, 0x1394: 0x1100, 0x1395: 0x1100, 0x1396: 0x1100, 0x1397: 0x1100,
+ 0x1398: 0x1100, 0x1399: 0x1100, 0x139a: 0x9900, 0x139b: 0x9900, 0x139c: 0x1100, 0x139d: 0x1100,
+ 0x139e: 0x1100, 0x139f: 0x1100, 0x13a0: 0x1100, 0x13a1: 0x1100, 0x13a2: 0x9900, 0x13a3: 0x9900,
+ 0x13a4: 0x1100, 0x13a5: 0x1100, 0x13a6: 0x1100, 0x13a7: 0x1100, 0x13a8: 0x1100, 0x13a9: 0x1100,
+ 0x13aa: 0x1100, 0x13ab: 0x1100, 0x13ac: 0x1100, 0x13ad: 0x1100, 0x13ae: 0x1100, 0x13af: 0x1100,
+ 0x13b0: 0x1100, 0x13b1: 0x1100, 0x13b2: 0x1100, 0x13b3: 0x1100, 0x13b4: 0x1100, 0x13b5: 0x1100,
+ 0x13b6: 0x1100, 0x13b7: 0x1100, 0x13b8: 0x1100, 0x13b9: 0x1100, 0x13ba: 0x1100, 0x13bb: 0x1100,
+ 0x13bc: 0x1100, 0x13bd: 0x1100, 0x13be: 0x1100, 0x13bf: 0x1100,
+ // Block 0x4f, offset 0x13c0
+ 0x13c0: 0x1100, 0x13c1: 0x1100, 0x13c2: 0x1100, 0x13c3: 0x1100, 0x13c4: 0x1100, 0x13c5: 0x1100,
+ 0x13c6: 0x1100, 0x13c7: 0x1100, 0x13c8: 0x1100, 0x13c9: 0x1100, 0x13ca: 0x1100, 0x13cb: 0x1100,
+ 0x13cc: 0x1100, 0x13cd: 0x1100, 0x13ce: 0x1100, 0x13cf: 0x1100, 0x13d0: 0x1100, 0x13d1: 0x1100,
+ 0x13d2: 0x1100, 0x13d3: 0x1100, 0x13d4: 0x1100, 0x13d5: 0x1100, 0x13d6: 0x1100, 0x13d7: 0x1100,
+ 0x13d8: 0x1100, 0x13d9: 0x1100, 0x13da: 0x3000, 0x13db: 0x3100,
+ 0x13e0: 0x9900, 0x13e1: 0x9900, 0x13e2: 0x1100, 0x13e3: 0x1100,
+ 0x13e4: 0x1100, 0x13e5: 0x1100, 0x13e6: 0x1100, 0x13e7: 0x1100, 0x13e8: 0x1100, 0x13e9: 0x1100,
+ 0x13ea: 0x1100, 0x13eb: 0x1100, 0x13ec: 0x1100, 0x13ed: 0x1100, 0x13ee: 0x1100, 0x13ef: 0x1100,
+ 0x13f0: 0x1100, 0x13f1: 0x1100, 0x13f2: 0x1100, 0x13f3: 0x1100, 0x13f4: 0x1100, 0x13f5: 0x1100,
+ 0x13f6: 0x1100, 0x13f7: 0x1100, 0x13f8: 0x9900, 0x13f9: 0x9900, 0x13fa: 0x1100, 0x13fb: 0x1100,
+ 0x13fc: 0x1100, 0x13fd: 0x1100, 0x13fe: 0x1100, 0x13ff: 0x1100,
+ // Block 0x50, offset 0x1400
+ 0x1400: 0x1100, 0x1401: 0x1100, 0x1402: 0x1100, 0x1403: 0x1100, 0x1404: 0x1100, 0x1405: 0x1100,
+ 0x1406: 0x1100, 0x1407: 0x1100, 0x1408: 0x1100, 0x1409: 0x1100, 0x140a: 0x1100, 0x140b: 0x1100,
+ 0x140c: 0x9900, 0x140d: 0x9900, 0x140e: 0x1100, 0x140f: 0x1100, 0x1410: 0x1100, 0x1411: 0x1100,
+ 0x1412: 0x1100, 0x1413: 0x1100, 0x1414: 0x1100, 0x1415: 0x1100, 0x1416: 0x1100, 0x1417: 0x1100,
+ 0x1418: 0x1100, 0x1419: 0x1100, 0x141a: 0x1100, 0x141b: 0x1100, 0x141c: 0x1100, 0x141d: 0x1100,
+ 0x141e: 0x1100, 0x141f: 0x1100, 0x1420: 0x1100, 0x1421: 0x1100, 0x1422: 0x1100, 0x1423: 0x1100,
+ 0x1424: 0x1100, 0x1425: 0x1100, 0x1426: 0x1100, 0x1427: 0x1100, 0x1428: 0x1100, 0x1429: 0x1100,
+ 0x142a: 0x1100, 0x142b: 0x1100, 0x142c: 0x1100, 0x142d: 0x1100, 0x142e: 0x1100, 0x142f: 0x1100,
+ 0x1430: 0x1100, 0x1431: 0x1100, 0x1432: 0x1100, 0x1433: 0x1100, 0x1434: 0x1100, 0x1435: 0x1100,
+ 0x1436: 0x1100, 0x1437: 0x1100, 0x1438: 0x1100, 0x1439: 0x1100,
+ // Block 0x51, offset 0x1440
+ 0x1440: 0x9900, 0x1441: 0x9900, 0x1442: 0x9900, 0x1443: 0x9900, 0x1444: 0x9900, 0x1445: 0x9900,
+ 0x1446: 0x9900, 0x1447: 0x9900, 0x1448: 0x9900, 0x1449: 0x9900, 0x144a: 0x9900, 0x144b: 0x9900,
+ 0x144c: 0x9900, 0x144d: 0x9900, 0x144e: 0x9900, 0x144f: 0x9900, 0x1450: 0x9900, 0x1451: 0x9900,
+ 0x1452: 0x1100, 0x1453: 0x1100, 0x1454: 0x1100, 0x1455: 0x1100,
+ 0x1458: 0x9900, 0x1459: 0x9900, 0x145a: 0x1100, 0x145b: 0x1100, 0x145c: 0x1100, 0x145d: 0x1100,
+ 0x1460: 0x9900, 0x1461: 0x9900, 0x1462: 0x9900, 0x1463: 0x9900,
+ 0x1464: 0x9900, 0x1465: 0x9900, 0x1466: 0x9900, 0x1467: 0x9900, 0x1468: 0x9900, 0x1469: 0x9900,
+ 0x146a: 0x9900, 0x146b: 0x9900, 0x146c: 0x9900, 0x146d: 0x9900, 0x146e: 0x9900, 0x146f: 0x9900,
+ 0x1470: 0x9900, 0x1471: 0x9900, 0x1472: 0x1100, 0x1473: 0x1100, 0x1474: 0x1100, 0x1475: 0x1100,
+ 0x1476: 0x1100, 0x1477: 0x1100, 0x1478: 0x9900, 0x1479: 0x9900, 0x147a: 0x1100, 0x147b: 0x1100,
+ 0x147c: 0x1100, 0x147d: 0x1100, 0x147e: 0x1100, 0x147f: 0x1100,
+ // Block 0x52, offset 0x1480
+ 0x1480: 0x9900, 0x1481: 0x9900, 0x1482: 0x1100, 0x1483: 0x1100, 0x1484: 0x1100, 0x1485: 0x1100,
+ 0x1488: 0x9900, 0x1489: 0x9900, 0x148a: 0x1100, 0x148b: 0x1100,
+ 0x148c: 0x1100, 0x148d: 0x1100, 0x1490: 0x9900, 0x1491: 0x9900,
+ 0x1492: 0x1100, 0x1493: 0x1100, 0x1494: 0x1100, 0x1495: 0x1100, 0x1496: 0x1100, 0x1497: 0x1100,
+ 0x1499: 0x9900, 0x149b: 0x1100, 0x149d: 0x1100,
+ 0x149f: 0x1100, 0x14a0: 0x9900, 0x14a1: 0x9900, 0x14a2: 0x9900, 0x14a3: 0x9900,
+ 0x14a4: 0x9900, 0x14a5: 0x9900, 0x14a6: 0x9900, 0x14a7: 0x9900, 0x14a8: 0x9900, 0x14a9: 0x9900,
+ 0x14aa: 0x9900, 0x14ab: 0x9900, 0x14ac: 0x9900, 0x14ad: 0x9900, 0x14ae: 0x9900, 0x14af: 0x9900,
+ 0x14b0: 0x9900, 0x14b1: 0x3300, 0x14b2: 0x1100, 0x14b3: 0x3300, 0x14b4: 0x9900, 0x14b5: 0x3300,
+ 0x14b6: 0x1100, 0x14b7: 0x3300, 0x14b8: 0x1100, 0x14b9: 0x3300, 0x14ba: 0x1100, 0x14bb: 0x3300,
+ 0x14bc: 0x9900, 0x14bd: 0x3300,
+ // Block 0x53, offset 0x14c0
+ 0x14c0: 0x1100, 0x14c1: 0x1100, 0x14c2: 0x1100, 0x14c3: 0x1100, 0x14c4: 0x1100, 0x14c5: 0x1100,
+ 0x14c6: 0x1100, 0x14c7: 0x1100, 0x14c8: 0x1100, 0x14c9: 0x1100, 0x14ca: 0x1100, 0x14cb: 0x1100,
+ 0x14cc: 0x1100, 0x14cd: 0x1100, 0x14ce: 0x1100, 0x14cf: 0x1100, 0x14d0: 0x1100, 0x14d1: 0x1100,
+ 0x14d2: 0x1100, 0x14d3: 0x1100, 0x14d4: 0x1100, 0x14d5: 0x1100, 0x14d6: 0x1100, 0x14d7: 0x1100,
+ 0x14d8: 0x1100, 0x14d9: 0x1100, 0x14da: 0x1100, 0x14db: 0x1100, 0x14dc: 0x1100, 0x14dd: 0x1100,
+ 0x14de: 0x1100, 0x14df: 0x1100, 0x14e0: 0x1100, 0x14e1: 0x1100, 0x14e2: 0x1100, 0x14e3: 0x1100,
+ 0x14e4: 0x1100, 0x14e5: 0x1100, 0x14e6: 0x1100, 0x14e7: 0x1100, 0x14e8: 0x1100, 0x14e9: 0x1100,
+ 0x14ea: 0x1100, 0x14eb: 0x1100, 0x14ec: 0x1100, 0x14ed: 0x1100, 0x14ee: 0x1100, 0x14ef: 0x1100,
+ 0x14f0: 0x1100, 0x14f1: 0x1100, 0x14f2: 0x1100, 0x14f3: 0x1100, 0x14f4: 0x1100,
+ 0x14f6: 0x9900, 0x14f7: 0x1100, 0x14f8: 0x1100, 0x14f9: 0x1100, 0x14fa: 0x1100, 0x14fb: 0x3300,
+ 0x14fc: 0x1100, 0x14fd: 0x3000, 0x14fe: 0x3300, 0x14ff: 0x3800,
+ // Block 0x54, offset 0x1500
+ 0x1500: 0x3000, 0x1501: 0x3100, 0x1502: 0x1100, 0x1503: 0x1100, 0x1504: 0x1100,
+ 0x1506: 0x9900, 0x1507: 0x1100, 0x1508: 0x1100, 0x1509: 0x3300, 0x150a: 0x1100, 0x150b: 0x3300,
+ 0x150c: 0x1100, 0x150d: 0x3100, 0x150e: 0x3100, 0x150f: 0x3100, 0x1510: 0x1100, 0x1511: 0x1100,
+ 0x1512: 0x1100, 0x1513: 0x3300, 0x1516: 0x1100, 0x1517: 0x1100,
+ 0x1518: 0x1100, 0x1519: 0x1100, 0x151a: 0x1100, 0x151b: 0x3300, 0x151d: 0x3100,
+ 0x151e: 0x3100, 0x151f: 0x3100, 0x1520: 0x1100, 0x1521: 0x1100, 0x1522: 0x1100, 0x1523: 0x3300,
+ 0x1524: 0x1100, 0x1525: 0x1100, 0x1526: 0x1100, 0x1527: 0x1100, 0x1528: 0x1100, 0x1529: 0x1100,
+ 0x152a: 0x1100, 0x152b: 0x3300, 0x152c: 0x1100, 0x152d: 0x3100, 0x152e: 0x3300, 0x152f: 0x3300,
+ 0x1532: 0x1100, 0x1533: 0x1100, 0x1534: 0x1100,
+ 0x1536: 0x9900, 0x1537: 0x1100, 0x1538: 0x1100, 0x1539: 0x3300, 0x153a: 0x1100, 0x153b: 0x3300,
+ 0x153c: 0x1100, 0x153d: 0x3300, 0x153e: 0x3800,
+ // Block 0x55, offset 0x1540
+ 0x1540: 0x3300, 0x1541: 0x3300, 0x1542: 0x3000, 0x1543: 0x3000, 0x1544: 0x3000, 0x1545: 0x3000,
+ 0x1546: 0x3000, 0x1547: 0x3000, 0x1548: 0x3000, 0x1549: 0x3000, 0x154a: 0x3000,
+ 0x1551: 0x3000,
+ 0x1557: 0x3000,
+ 0x1564: 0x3000, 0x1565: 0x3000, 0x1566: 0x3000,
+ 0x156f: 0x3000,
+ 0x1573: 0x3000, 0x1574: 0x3000,
+ 0x1576: 0x3000, 0x1577: 0x3000,
+ 0x157c: 0x3000, 0x157e: 0x3000,
+ // Block 0x56, offset 0x1580
+ 0x1587: 0x3000, 0x1588: 0x3000, 0x1589: 0x3000,
+ 0x1597: 0x3000,
+ 0x159f: 0x3000,
+ 0x15b0: 0x3000, 0x15b1: 0x3000, 0x15b4: 0x3000, 0x15b5: 0x3000,
+ 0x15b6: 0x3000, 0x15b7: 0x3000, 0x15b8: 0x3000, 0x15b9: 0x3000, 0x15ba: 0x3000, 0x15bb: 0x3000,
+ 0x15bc: 0x3000, 0x15bd: 0x3000, 0x15be: 0x3000, 0x15bf: 0x3000,
+ // Block 0x57, offset 0x15c0
+ 0x15c0: 0x3000, 0x15c1: 0x3000, 0x15c2: 0x3000, 0x15c3: 0x3000, 0x15c4: 0x3000, 0x15c5: 0x3000,
+ 0x15c6: 0x3000, 0x15c7: 0x3000, 0x15c8: 0x3000, 0x15c9: 0x3000, 0x15ca: 0x3000, 0x15cb: 0x3000,
+ 0x15cc: 0x3000, 0x15cd: 0x3000, 0x15ce: 0x3000, 0x15d0: 0x3000, 0x15d1: 0x3000,
+ 0x15d2: 0x3000, 0x15d3: 0x3000, 0x15d4: 0x3000, 0x15d5: 0x3000, 0x15d6: 0x3000, 0x15d7: 0x3000,
+ 0x15d8: 0x3000, 0x15d9: 0x3000, 0x15da: 0x3000, 0x15db: 0x3000, 0x15dc: 0x3000,
+ 0x15e8: 0x3000,
+ // Block 0x58, offset 0x1600
+ 0x1610: 0x00e6, 0x1611: 0x00e6,
+ 0x1612: 0x0001, 0x1613: 0x0001, 0x1614: 0x00e6, 0x1615: 0x00e6, 0x1616: 0x00e6, 0x1617: 0x00e6,
+ 0x1618: 0x0001, 0x1619: 0x0001, 0x161a: 0x0001, 0x161b: 0x00e6, 0x161c: 0x00e6,
+ 0x1621: 0x00e6,
+ 0x1625: 0x0001, 0x1626: 0x0001, 0x1627: 0x00e6, 0x1628: 0x00dc, 0x1629: 0x00e6,
+ 0x162a: 0x0001, 0x162b: 0x0001, 0x162c: 0x00dc, 0x162d: 0x00dc, 0x162e: 0x00dc, 0x162f: 0x00dc,
+ 0x1630: 0x00e6,
+ // Block 0x59, offset 0x1640
+ 0x1640: 0x3000, 0x1641: 0x3000, 0x1642: 0x3000, 0x1643: 0x3000, 0x1645: 0x3000,
+ 0x1646: 0x3000, 0x1647: 0x3000, 0x1649: 0x3000, 0x164a: 0x3000, 0x164b: 0x3000,
+ 0x164c: 0x3000, 0x164d: 0x3000, 0x164e: 0x3000, 0x164f: 0x3000, 0x1650: 0x3000, 0x1651: 0x3000,
+ 0x1652: 0x3000, 0x1653: 0x3000, 0x1655: 0x3000, 0x1656: 0x3000,
+ 0x1659: 0x3000, 0x165a: 0x3000, 0x165b: 0x3000, 0x165c: 0x3000, 0x165d: 0x3000,
+ 0x1660: 0x3000, 0x1661: 0x3000, 0x1662: 0x3000,
+ 0x1664: 0x3000, 0x1666: 0x3300, 0x1668: 0x3000,
+ 0x166a: 0x3300, 0x166b: 0x3300, 0x166c: 0x3000, 0x166d: 0x3000, 0x166f: 0x3000,
+ 0x1670: 0x3000, 0x1671: 0x3000, 0x1673: 0x3000, 0x1674: 0x3000, 0x1675: 0x3000,
+ 0x1676: 0x3000, 0x1677: 0x3000, 0x1678: 0x3000, 0x1679: 0x3000, 0x167b: 0x3000,
+ 0x167c: 0x3000, 0x167d: 0x3000, 0x167e: 0x3000, 0x167f: 0x3000,
+ // Block 0x5a, offset 0x1680
+ 0x1680: 0x3000, 0x1685: 0x3000,
+ 0x1686: 0x3000, 0x1687: 0x3000, 0x1688: 0x3000, 0x1689: 0x3000,
+ 0x1690: 0x3000, 0x1691: 0x3000,
+ 0x1692: 0x3000, 0x1693: 0x3000, 0x1694: 0x3000, 0x1695: 0x3000, 0x1696: 0x3000, 0x1697: 0x3000,
+ 0x1698: 0x3000, 0x1699: 0x3000, 0x169a: 0x3000, 0x169b: 0x3000, 0x169c: 0x3000, 0x169d: 0x3000,
+ 0x169e: 0x3000, 0x169f: 0x3000, 0x16a0: 0x3000, 0x16a1: 0x3000, 0x16a2: 0x3000, 0x16a3: 0x3000,
+ 0x16a4: 0x3000, 0x16a5: 0x3000, 0x16a6: 0x3000, 0x16a7: 0x3000, 0x16a8: 0x3000, 0x16a9: 0x3000,
+ 0x16aa: 0x3000, 0x16ab: 0x3000, 0x16ac: 0x3000, 0x16ad: 0x3000, 0x16ae: 0x3000, 0x16af: 0x3000,
+ 0x16b0: 0x3000, 0x16b1: 0x3000, 0x16b2: 0x3000, 0x16b3: 0x3000, 0x16b4: 0x3000, 0x16b5: 0x3000,
+ 0x16b6: 0x3000, 0x16b7: 0x3000, 0x16b8: 0x3000, 0x16b9: 0x3000, 0x16ba: 0x3000, 0x16bb: 0x3000,
+ 0x16bc: 0x3000, 0x16bd: 0x3000, 0x16be: 0x3000, 0x16bf: 0x3000,
+ // Block 0x5b, offset 0x16c0
+ 0x16c9: 0x3000,
+ 0x16d0: 0x8800,
+ 0x16d2: 0x8800, 0x16d4: 0x8800,
+ 0x16da: 0x1100, 0x16db: 0x1100,
+ 0x16ee: 0x1100,
+ // Block 0x5c, offset 0x1700
+ 0x170d: 0x1100, 0x170e: 0x1100, 0x170f: 0x1100, 0x1710: 0x8800,
+ 0x1712: 0x8800, 0x1714: 0x8800,
+ // Block 0x5d, offset 0x1740
+ 0x1743: 0x8800, 0x1744: 0x1100,
+ 0x1748: 0x8800, 0x1749: 0x1100, 0x174b: 0x8800,
+ 0x174c: 0x1100,
+ 0x1763: 0x8800,
+ 0x1764: 0x1100, 0x1765: 0x8800, 0x1766: 0x1100,
+ 0x176c: 0x3000, 0x176d: 0x3000, 0x176f: 0x3000,
+ 0x1770: 0x3000,
+ 0x177c: 0x8800,
+ // Block 0x5e, offset 0x1780
+ 0x1781: 0x1100, 0x1783: 0x8800, 0x1784: 0x1100, 0x1785: 0x8800,
+ 0x1787: 0x1100, 0x1788: 0x8800, 0x1789: 0x1100,
+ 0x178d: 0x8800,
+ 0x17a0: 0x1100, 0x17a1: 0x8800, 0x17a2: 0x1100,
+ 0x17a4: 0x8800, 0x17a5: 0x8800,
+ 0x17ad: 0x1100, 0x17ae: 0x1100, 0x17af: 0x1100,
+ 0x17b0: 0x1100, 0x17b1: 0x1100, 0x17b2: 0x8800, 0x17b3: 0x8800, 0x17b4: 0x1100, 0x17b5: 0x1100,
+ 0x17b6: 0x8800, 0x17b7: 0x8800, 0x17b8: 0x1100, 0x17b9: 0x1100, 0x17ba: 0x8800, 0x17bb: 0x8800,
+ 0x17bc: 0x8800, 0x17bd: 0x8800,
+ // Block 0x5f, offset 0x17c0
+ 0x17c0: 0x1100, 0x17c1: 0x1100, 0x17c2: 0x8800, 0x17c3: 0x8800, 0x17c4: 0x1100, 0x17c5: 0x1100,
+ 0x17c6: 0x8800, 0x17c7: 0x8800, 0x17c8: 0x1100, 0x17c9: 0x1100,
+ 0x17d1: 0x8800,
+ 0x17d2: 0x8800,
+ 0x17e2: 0x8800,
+ 0x17e8: 0x8800, 0x17e9: 0x8800,
+ 0x17eb: 0x8800, 0x17ec: 0x1100, 0x17ed: 0x1100, 0x17ee: 0x1100, 0x17ef: 0x1100,
+ 0x17f2: 0x8800, 0x17f3: 0x8800, 0x17f4: 0x8800, 0x17f5: 0x8800,
+ // Block 0x60, offset 0x1800
+ 0x1820: 0x1100, 0x1821: 0x1100, 0x1822: 0x1100, 0x1823: 0x1100,
+ 0x182a: 0x1100, 0x182b: 0x1100, 0x182c: 0x1100, 0x182d: 0x1100,
+ // Block 0x61, offset 0x1840
+ 0x1869: 0x3300,
+ 0x186a: 0x3300,
+ // Block 0x62, offset 0x1880
+ 0x18a0: 0x3000, 0x18a1: 0x3000, 0x18a2: 0x3000, 0x18a3: 0x3000,
+ 0x18a4: 0x3000, 0x18a5: 0x3000, 0x18a6: 0x3000, 0x18a7: 0x3000, 0x18a8: 0x3000, 0x18a9: 0x3000,
+ 0x18aa: 0x3000, 0x18ab: 0x3000, 0x18ac: 0x3000, 0x18ad: 0x3000, 0x18ae: 0x3000, 0x18af: 0x3000,
+ 0x18b0: 0x3000, 0x18b1: 0x3000, 0x18b2: 0x3000, 0x18b3: 0x3000, 0x18b4: 0x3000, 0x18b5: 0x3000,
+ 0x18b6: 0x3000, 0x18b7: 0x3000, 0x18b8: 0x3000, 0x18b9: 0x3000, 0x18ba: 0x3000, 0x18bb: 0x3000,
+ 0x18bc: 0x3000, 0x18bd: 0x3000, 0x18be: 0x3000, 0x18bf: 0x3000,
+ // Block 0x63, offset 0x18c0
+ 0x18c0: 0x3000, 0x18c1: 0x3000, 0x18c2: 0x3000, 0x18c3: 0x3000, 0x18c4: 0x3000, 0x18c5: 0x3000,
+ 0x18c6: 0x3000, 0x18c7: 0x3000, 0x18c8: 0x3000, 0x18c9: 0x3000, 0x18ca: 0x3000, 0x18cb: 0x3000,
+ 0x18cc: 0x3000, 0x18cd: 0x3000, 0x18ce: 0x3000, 0x18cf: 0x3000, 0x18d0: 0x3000, 0x18d1: 0x3000,
+ 0x18d2: 0x3000, 0x18d3: 0x3000, 0x18d4: 0x3000, 0x18d5: 0x3000, 0x18d6: 0x3000, 0x18d7: 0x3000,
+ 0x18d8: 0x3000, 0x18d9: 0x3000, 0x18da: 0x3000, 0x18db: 0x3000, 0x18dc: 0x3000, 0x18dd: 0x3000,
+ 0x18de: 0x3000, 0x18df: 0x3000, 0x18e0: 0x3000, 0x18e1: 0x3000, 0x18e2: 0x3000, 0x18e3: 0x3000,
+ 0x18e4: 0x3000, 0x18e5: 0x3000, 0x18e6: 0x3000, 0x18e7: 0x3000, 0x18e8: 0x3000, 0x18e9: 0x3000,
+ 0x18ea: 0x3000, 0x18eb: 0x3000, 0x18ec: 0x3000, 0x18ed: 0x3000, 0x18ee: 0x3000, 0x18ef: 0x3000,
+ 0x18f0: 0x3000, 0x18f1: 0x3000, 0x18f2: 0x3000, 0x18f3: 0x3000, 0x18f4: 0x3000, 0x18f5: 0x3000,
+ 0x18f6: 0x3000, 0x18f7: 0x3000, 0x18f8: 0x3000, 0x18f9: 0x3000, 0x18fa: 0x3000, 0x18fb: 0x3000,
+ 0x18fc: 0x3000, 0x18fd: 0x3000, 0x18fe: 0x3000, 0x18ff: 0x3000,
+ // Block 0x64, offset 0x1900
+ 0x1900: 0x3000, 0x1901: 0x3000, 0x1902: 0x3000, 0x1903: 0x3000, 0x1904: 0x3000, 0x1905: 0x3000,
+ 0x1906: 0x3000, 0x1907: 0x3000, 0x1908: 0x3000, 0x1909: 0x3000, 0x190a: 0x3000, 0x190b: 0x3000,
+ 0x190c: 0x3000, 0x190d: 0x3000, 0x190e: 0x3000, 0x190f: 0x3000, 0x1910: 0x3000, 0x1911: 0x3000,
+ 0x1912: 0x3000, 0x1913: 0x3000, 0x1914: 0x3000, 0x1915: 0x3000, 0x1916: 0x3000, 0x1917: 0x3000,
+ 0x1918: 0x3000, 0x1919: 0x3000, 0x191a: 0x3000, 0x191b: 0x3000, 0x191c: 0x3000, 0x191d: 0x3000,
+ 0x191e: 0x3000, 0x191f: 0x3000, 0x1920: 0x3000, 0x1921: 0x3000, 0x1922: 0x3000, 0x1923: 0x3000,
+ 0x1924: 0x3000, 0x1925: 0x3000, 0x1926: 0x3000, 0x1927: 0x3000, 0x1928: 0x3000, 0x1929: 0x3000,
+ 0x192a: 0x3000,
+ // Block 0x65, offset 0x1940
+ 0x194c: 0x3000,
+ // Block 0x66, offset 0x1980
+ 0x19b4: 0x3000, 0x19b5: 0x3000,
+ 0x19b6: 0x3000,
+ // Block 0x67, offset 0x19c0
+ 0x19dc: 0x3300,
+ // Block 0x68, offset 0x1a00
+ 0x1a3c: 0x3000, 0x1a3d: 0x3000,
+ // Block 0x69, offset 0x1a40
+ 0x1a6f: 0x00e6,
+ 0x1a70: 0x00e6, 0x1a71: 0x00e6,
+ // Block 0x6a, offset 0x1a80
+ 0x1aaf: 0x3000,
+ 0x1abf: 0x0009,
+ // Block 0x6b, offset 0x1ac0
+ 0x1ae0: 0x00e6, 0x1ae1: 0x00e6, 0x1ae2: 0x00e6, 0x1ae3: 0x00e6,
+ 0x1ae4: 0x00e6, 0x1ae5: 0x00e6, 0x1ae6: 0x00e6, 0x1ae7: 0x00e6, 0x1ae8: 0x00e6, 0x1ae9: 0x00e6,
+ 0x1aea: 0x00e6, 0x1aeb: 0x00e6, 0x1aec: 0x00e6, 0x1aed: 0x00e6, 0x1aee: 0x00e6, 0x1aef: 0x00e6,
+ 0x1af0: 0x00e6, 0x1af1: 0x00e6, 0x1af2: 0x00e6, 0x1af3: 0x00e6, 0x1af4: 0x00e6, 0x1af5: 0x00e6,
+ 0x1af6: 0x00e6, 0x1af7: 0x00e6, 0x1af8: 0x00e6, 0x1af9: 0x00e6, 0x1afa: 0x00e6, 0x1afb: 0x00e6,
+ 0x1afc: 0x00e6, 0x1afd: 0x00e6, 0x1afe: 0x00e6, 0x1aff: 0x00e6,
+ // Block 0x6c, offset 0x1b00
+ 0x1b1f: 0x3000,
+ // Block 0x6d, offset 0x1b40
+ 0x1b73: 0x3000,
+ // Block 0x6e, offset 0x1b80
+ 0x1b80: 0x3000, 0x1b81: 0x3000, 0x1b82: 0x3000, 0x1b83: 0x3000, 0x1b84: 0x3000, 0x1b85: 0x3000,
+ 0x1b86: 0x3000, 0x1b87: 0x3000, 0x1b88: 0x3000, 0x1b89: 0x3000, 0x1b8a: 0x3000, 0x1b8b: 0x3000,
+ 0x1b8c: 0x3000, 0x1b8d: 0x3000, 0x1b8e: 0x3000, 0x1b8f: 0x3000, 0x1b90: 0x3000, 0x1b91: 0x3000,
+ 0x1b92: 0x3000, 0x1b93: 0x3000, 0x1b94: 0x3000, 0x1b95: 0x3000,
+ // Block 0x6f, offset 0x1bc0
+ 0x1bc0: 0x3000,
+ 0x1bea: 0x00da, 0x1beb: 0x00e4, 0x1bec: 0x00e8, 0x1bed: 0x00de, 0x1bee: 0x00e0, 0x1bef: 0x00e0,
+ 0x1bf6: 0x3000, 0x1bf8: 0x3000, 0x1bf9: 0x3000, 0x1bfa: 0x3000,
+ // Block 0x70, offset 0x1c00
+ 0x1c06: 0x8800, 0x1c0b: 0x8800,
+ 0x1c0c: 0x1100, 0x1c0d: 0x8800, 0x1c0e: 0x1100, 0x1c0f: 0x8800, 0x1c10: 0x1100, 0x1c11: 0x8800,
+ 0x1c12: 0x1100, 0x1c13: 0x8800, 0x1c14: 0x1100, 0x1c15: 0x8800, 0x1c16: 0x1100, 0x1c17: 0x8800,
+ 0x1c18: 0x1100, 0x1c19: 0x8800, 0x1c1a: 0x1100, 0x1c1b: 0x8800, 0x1c1c: 0x1100, 0x1c1d: 0x8800,
+ 0x1c1e: 0x1100, 0x1c1f: 0x8800, 0x1c20: 0x1100, 0x1c21: 0x8800, 0x1c22: 0x1100,
+ 0x1c24: 0x8800, 0x1c25: 0x1100, 0x1c26: 0x8800, 0x1c27: 0x1100, 0x1c28: 0x8800, 0x1c29: 0x1100,
+ 0x1c2f: 0x8800,
+ 0x1c30: 0x1100, 0x1c31: 0x1100, 0x1c32: 0x8800, 0x1c33: 0x1100, 0x1c34: 0x1100, 0x1c35: 0x8800,
+ 0x1c36: 0x1100, 0x1c37: 0x1100, 0x1c38: 0x8800, 0x1c39: 0x1100, 0x1c3a: 0x1100, 0x1c3b: 0x8800,
+ 0x1c3c: 0x1100, 0x1c3d: 0x1100,
+ // Block 0x71, offset 0x1c40
+ 0x1c54: 0x1100,
+ 0x1c59: 0x6608, 0x1c5a: 0x6608, 0x1c5b: 0x3000, 0x1c5c: 0x3000, 0x1c5d: 0x8800,
+ 0x1c5e: 0x1100, 0x1c5f: 0x3000,
+ 0x1c66: 0x8800,
+ 0x1c6b: 0x8800, 0x1c6c: 0x1100, 0x1c6d: 0x8800, 0x1c6e: 0x1100, 0x1c6f: 0x8800,
+ 0x1c70: 0x1100, 0x1c71: 0x8800, 0x1c72: 0x1100, 0x1c73: 0x8800, 0x1c74: 0x1100, 0x1c75: 0x8800,
+ 0x1c76: 0x1100, 0x1c77: 0x8800, 0x1c78: 0x1100, 0x1c79: 0x8800, 0x1c7a: 0x1100, 0x1c7b: 0x8800,
+ 0x1c7c: 0x1100, 0x1c7d: 0x8800, 0x1c7e: 0x1100, 0x1c7f: 0x8800,
+ // Block 0x72, offset 0x1c80
+ 0x1c80: 0x1100, 0x1c81: 0x8800, 0x1c82: 0x1100, 0x1c84: 0x8800, 0x1c85: 0x1100,
+ 0x1c86: 0x8800, 0x1c87: 0x1100, 0x1c88: 0x8800, 0x1c89: 0x1100,
+ 0x1c8f: 0x8800, 0x1c90: 0x1100, 0x1c91: 0x1100,
+ 0x1c92: 0x8800, 0x1c93: 0x1100, 0x1c94: 0x1100, 0x1c95: 0x8800, 0x1c96: 0x1100, 0x1c97: 0x1100,
+ 0x1c98: 0x8800, 0x1c99: 0x1100, 0x1c9a: 0x1100, 0x1c9b: 0x8800, 0x1c9c: 0x1100, 0x1c9d: 0x1100,
+ 0x1caf: 0x8800,
+ 0x1cb0: 0x8800, 0x1cb1: 0x8800, 0x1cb2: 0x8800, 0x1cb4: 0x1100,
+ 0x1cb7: 0x1100, 0x1cb8: 0x1100, 0x1cb9: 0x1100, 0x1cba: 0x1100,
+ 0x1cbd: 0x8800, 0x1cbe: 0x1100, 0x1cbf: 0x3000,
+ // Block 0x73, offset 0x1cc0
+ 0x1cf1: 0x3000, 0x1cf2: 0x3000, 0x1cf3: 0x3000, 0x1cf4: 0x3000, 0x1cf5: 0x3000,
+ 0x1cf6: 0x3000, 0x1cf7: 0x3000, 0x1cf8: 0x3000, 0x1cf9: 0x3000, 0x1cfa: 0x3000, 0x1cfb: 0x3000,
+ 0x1cfc: 0x3000, 0x1cfd: 0x3000, 0x1cfe: 0x3000, 0x1cff: 0x3000,
+ // Block 0x74, offset 0x1d00
+ 0x1d00: 0x3000, 0x1d01: 0x3000, 0x1d02: 0x3000, 0x1d03: 0x3000, 0x1d04: 0x3000, 0x1d05: 0x3000,
+ 0x1d06: 0x3000, 0x1d07: 0x3000, 0x1d08: 0x3000, 0x1d09: 0x3000, 0x1d0a: 0x3000, 0x1d0b: 0x3000,
+ 0x1d0c: 0x3000, 0x1d0d: 0x3000, 0x1d0e: 0x3000,
+ 0x1d12: 0x3000, 0x1d13: 0x3000, 0x1d14: 0x3000, 0x1d15: 0x3000, 0x1d16: 0x3000, 0x1d17: 0x3000,
+ 0x1d18: 0x3000, 0x1d19: 0x3000, 0x1d1a: 0x3000, 0x1d1b: 0x3000, 0x1d1c: 0x3000, 0x1d1d: 0x3000,
+ 0x1d1e: 0x3000, 0x1d1f: 0x3000,
+ // Block 0x75, offset 0x1d40
+ 0x1d40: 0x3000, 0x1d41: 0x3000, 0x1d42: 0x3000, 0x1d43: 0x3000, 0x1d44: 0x3000, 0x1d45: 0x3000,
+ 0x1d46: 0x3000, 0x1d47: 0x3000, 0x1d48: 0x3000, 0x1d49: 0x3000, 0x1d4a: 0x3000, 0x1d4b: 0x3000,
+ 0x1d4c: 0x3000, 0x1d4d: 0x3000, 0x1d4e: 0x3000, 0x1d4f: 0x3000, 0x1d50: 0x3000, 0x1d51: 0x3000,
+ 0x1d52: 0x3000, 0x1d53: 0x3000, 0x1d54: 0x3000, 0x1d55: 0x3000, 0x1d56: 0x3000, 0x1d57: 0x3000,
+ 0x1d58: 0x3000, 0x1d59: 0x3000, 0x1d5a: 0x3000, 0x1d5b: 0x3000, 0x1d5c: 0x3000, 0x1d5d: 0x3000,
+ 0x1d5e: 0x3000, 0x1d60: 0x3000, 0x1d61: 0x3000, 0x1d62: 0x3000, 0x1d63: 0x3000,
+ 0x1d64: 0x3000, 0x1d65: 0x3000, 0x1d66: 0x3000, 0x1d67: 0x3000, 0x1d68: 0x3000, 0x1d69: 0x3000,
+ 0x1d6a: 0x3000, 0x1d6b: 0x3000, 0x1d6c: 0x3000, 0x1d6d: 0x3000, 0x1d6e: 0x3000, 0x1d6f: 0x3000,
+ 0x1d70: 0x3000, 0x1d71: 0x3000, 0x1d72: 0x3000, 0x1d73: 0x3000, 0x1d74: 0x3000, 0x1d75: 0x3000,
+ 0x1d76: 0x3000, 0x1d77: 0x3000, 0x1d78: 0x3000, 0x1d79: 0x3000, 0x1d7a: 0x3000, 0x1d7b: 0x3000,
+ 0x1d7c: 0x3000, 0x1d7d: 0x3000, 0x1d7e: 0x3000, 0x1d7f: 0x3000,
+ // Block 0x76, offset 0x1d80
+ 0x1d80: 0x3000, 0x1d81: 0x3000, 0x1d82: 0x3000, 0x1d83: 0x3000, 0x1d84: 0x3000, 0x1d85: 0x3000,
+ 0x1d86: 0x3000, 0x1d87: 0x3000,
+ 0x1d90: 0x3000, 0x1d91: 0x3000,
+ 0x1d92: 0x3000, 0x1d93: 0x3000, 0x1d94: 0x3000, 0x1d95: 0x3000, 0x1d96: 0x3000, 0x1d97: 0x3000,
+ 0x1d98: 0x3000, 0x1d99: 0x3000, 0x1d9a: 0x3000, 0x1d9b: 0x3000, 0x1d9c: 0x3000, 0x1d9d: 0x3000,
+ 0x1d9e: 0x3000, 0x1d9f: 0x3000, 0x1da0: 0x3000, 0x1da1: 0x3000, 0x1da2: 0x3000, 0x1da3: 0x3000,
+ 0x1da4: 0x3000, 0x1da5: 0x3000, 0x1da6: 0x3000, 0x1da7: 0x3000, 0x1da8: 0x3000, 0x1da9: 0x3000,
+ 0x1daa: 0x3000, 0x1dab: 0x3000, 0x1dac: 0x3000, 0x1dad: 0x3000, 0x1dae: 0x3000, 0x1daf: 0x3000,
+ 0x1db0: 0x3000, 0x1db1: 0x3000, 0x1db2: 0x3000, 0x1db3: 0x3000, 0x1db4: 0x3000, 0x1db5: 0x3000,
+ 0x1db6: 0x3000, 0x1db7: 0x3000, 0x1db8: 0x3000, 0x1db9: 0x3000, 0x1dba: 0x3000, 0x1dbb: 0x3000,
+ 0x1dbc: 0x3000, 0x1dbd: 0x3000, 0x1dbe: 0x3000,
+ // Block 0x77, offset 0x1dc0
+ 0x1dc0: 0x3000, 0x1dc1: 0x3000, 0x1dc2: 0x3000, 0x1dc3: 0x3000, 0x1dc4: 0x3000, 0x1dc5: 0x3000,
+ 0x1dc6: 0x3000, 0x1dc7: 0x3000, 0x1dc8: 0x3000, 0x1dc9: 0x3000, 0x1dca: 0x3000, 0x1dcb: 0x3000,
+ 0x1dcc: 0x3000, 0x1dcd: 0x3000, 0x1dce: 0x3000, 0x1dcf: 0x3000, 0x1dd0: 0x3000, 0x1dd1: 0x3000,
+ 0x1dd2: 0x3000, 0x1dd3: 0x3000, 0x1dd4: 0x3000, 0x1dd5: 0x3000, 0x1dd6: 0x3000, 0x1dd7: 0x3000,
+ 0x1dd8: 0x3000, 0x1dd9: 0x3000, 0x1dda: 0x3000, 0x1ddb: 0x3000, 0x1ddc: 0x3000, 0x1ddd: 0x3000,
+ 0x1dde: 0x3000, 0x1ddf: 0x3000, 0x1de0: 0x3000, 0x1de1: 0x3000, 0x1de2: 0x3000, 0x1de3: 0x3000,
+ 0x1de4: 0x3000, 0x1de5: 0x3000, 0x1de6: 0x3000, 0x1de7: 0x3000, 0x1de8: 0x3000, 0x1de9: 0x3000,
+ 0x1dea: 0x3000, 0x1deb: 0x3000, 0x1dec: 0x3000, 0x1ded: 0x3000, 0x1dee: 0x3000, 0x1def: 0x3000,
+ 0x1df0: 0x3000, 0x1df1: 0x3000, 0x1df2: 0x3000, 0x1df3: 0x3000, 0x1df4: 0x3000, 0x1df5: 0x3000,
+ 0x1df6: 0x3000, 0x1df7: 0x3000, 0x1df8: 0x3000, 0x1df9: 0x3000, 0x1dfa: 0x3000, 0x1dfb: 0x3000,
+ 0x1dfc: 0x3000, 0x1dfd: 0x3000, 0x1dfe: 0x3000,
+ // Block 0x78, offset 0x1e00
+ 0x1e2f: 0x00e6,
+ 0x1e3c: 0x00e6, 0x1e3d: 0x00e6,
+ // Block 0x79, offset 0x1e40
+ 0x1e70: 0x00e6, 0x1e71: 0x00e6,
+ // Block 0x7a, offset 0x1e80
+ 0x1eb0: 0x3000,
+ // Block 0x7b, offset 0x1ec0
+ 0x1ec6: 0x0009,
+ // Block 0x7c, offset 0x1f00
+ 0x1f04: 0x0009,
+ 0x1f20: 0x00e6, 0x1f21: 0x00e6, 0x1f22: 0x00e6, 0x1f23: 0x00e6,
+ 0x1f24: 0x00e6, 0x1f25: 0x00e6, 0x1f26: 0x00e6, 0x1f27: 0x00e6, 0x1f28: 0x00e6, 0x1f29: 0x00e6,
+ 0x1f2a: 0x00e6, 0x1f2b: 0x00e6, 0x1f2c: 0x00e6, 0x1f2d: 0x00e6, 0x1f2e: 0x00e6, 0x1f2f: 0x00e6,
+ 0x1f30: 0x00e6, 0x1f31: 0x00e6,
+ // Block 0x7d, offset 0x1f40
+ 0x1f6b: 0x00dc, 0x1f6c: 0x00dc, 0x1f6d: 0x00dc,
+ // Block 0x7e, offset 0x1f80
+ 0x1f93: 0x0009,
+ // Block 0x7f, offset 0x1fc0
+ 0x1ff3: 0x0007,
+ // Block 0x80, offset 0x2000
+ 0x2000: 0x0009,
+ // Block 0x81, offset 0x2040
+ 0x2070: 0x00e6, 0x2072: 0x00e6, 0x2073: 0x00e6, 0x2074: 0x00dc,
+ 0x2077: 0x00e6, 0x2078: 0x00e6,
+ 0x207e: 0x00e6, 0x207f: 0x00e6,
+ // Block 0x82, offset 0x2080
+ 0x2081: 0x00e6,
+ // Block 0x83, offset 0x20c0
+ 0x20ed: 0x0009,
+ // Block 0x84, offset 0x2100
+ 0x2100: 0x1100, 0x2101: 0x1100, 0x2102: 0x1100, 0x2103: 0x1100, 0x2104: 0x1100, 0x2105: 0x1100,
+ 0x2106: 0x1100, 0x2107: 0x1100, 0x2108: 0x1100, 0x2109: 0x1100, 0x210a: 0x1100, 0x210b: 0x1100,
+ 0x210c: 0x1100, 0x210d: 0x1100, 0x210e: 0x1100, 0x210f: 0x1100, 0x2110: 0x1100, 0x2111: 0x1100,
+ 0x2112: 0x1100, 0x2113: 0x1100, 0x2114: 0x1100, 0x2115: 0x1100, 0x2116: 0x1100, 0x2117: 0x1100,
+ 0x2118: 0x1100, 0x2119: 0x1100, 0x211a: 0x1100, 0x211b: 0x1100, 0x211c: 0x1100, 0x211d: 0x1100,
+ 0x211e: 0x1100, 0x211f: 0x1100, 0x2120: 0x1100, 0x2121: 0x1100, 0x2122: 0x1100, 0x2123: 0x1100,
+ 0x2124: 0x1100, 0x2125: 0x1100, 0x2126: 0x1100, 0x2127: 0x1100, 0x2128: 0x1100, 0x2129: 0x1100,
+ 0x212a: 0x1100, 0x212b: 0x1100, 0x212c: 0x1100, 0x212d: 0x1100, 0x212e: 0x1100, 0x212f: 0x1100,
+ 0x2130: 0x1100, 0x2131: 0x1100, 0x2132: 0x1100, 0x2133: 0x1100, 0x2134: 0x1100, 0x2135: 0x1100,
+ 0x2136: 0x1100, 0x2137: 0x1100, 0x2138: 0x1100, 0x2139: 0x1100, 0x213a: 0x1100, 0x213b: 0x1100,
+ 0x213c: 0x1100, 0x213d: 0x1100, 0x213e: 0x1100, 0x213f: 0x1100,
+ // Block 0x85, offset 0x2140
+ 0x2140: 0x1100, 0x2141: 0x1100, 0x2142: 0x1100, 0x2143: 0x1100, 0x2144: 0x1100, 0x2145: 0x1100,
+ 0x2146: 0x1100, 0x2147: 0x1100, 0x2148: 0x1100, 0x2149: 0x1100, 0x214a: 0x1100, 0x214b: 0x1100,
+ 0x214c: 0x1100, 0x214d: 0x1100, 0x214e: 0x1100, 0x214f: 0x1100, 0x2150: 0x1100, 0x2151: 0x1100,
+ 0x2152: 0x1100, 0x2153: 0x1100, 0x2154: 0x1100, 0x2155: 0x1100, 0x2156: 0x1100, 0x2157: 0x1100,
+ 0x2158: 0x1100, 0x2159: 0x1100, 0x215a: 0x1100, 0x215b: 0x1100, 0x215c: 0x1100, 0x215d: 0x1100,
+ 0x215e: 0x1100, 0x215f: 0x1100, 0x2160: 0x1100, 0x2161: 0x1100, 0x2162: 0x1100, 0x2163: 0x1100,
+ // Block 0x86, offset 0x2180
+ 0x2180: 0x3300, 0x2181: 0x3300, 0x2182: 0x3300, 0x2183: 0x3300, 0x2184: 0x3300, 0x2185: 0x3300,
+ 0x2186: 0x3300, 0x2187: 0x3300, 0x2188: 0x3300, 0x2189: 0x3300, 0x218a: 0x3300, 0x218b: 0x3300,
+ 0x218c: 0x3300, 0x218d: 0x3300, 0x218e: 0x3300, 0x218f: 0x3300, 0x2190: 0x3300, 0x2191: 0x3300,
+ 0x2192: 0x3300, 0x2193: 0x3300, 0x2194: 0x3300, 0x2195: 0x3300, 0x2196: 0x3300, 0x2197: 0x3300,
+ 0x2198: 0x3300, 0x2199: 0x3300, 0x219a: 0x3300, 0x219b: 0x3300, 0x219c: 0x3300, 0x219d: 0x3300,
+ 0x219e: 0x3300, 0x219f: 0x3300, 0x21a0: 0x3300, 0x21a1: 0x3300, 0x21a2: 0x3300, 0x21a3: 0x3300,
+ 0x21a4: 0x3300, 0x21a5: 0x3300, 0x21a6: 0x3300, 0x21a7: 0x3300, 0x21a8: 0x3300, 0x21a9: 0x3300,
+ 0x21aa: 0x3300, 0x21ab: 0x3300, 0x21ac: 0x3300, 0x21ad: 0x3300, 0x21ae: 0x3300, 0x21af: 0x3300,
+ 0x21b0: 0x3300, 0x21b1: 0x3300, 0x21b2: 0x3300, 0x21b3: 0x3300, 0x21b4: 0x3300, 0x21b5: 0x3300,
+ 0x21b6: 0x3300, 0x21b7: 0x3300, 0x21b8: 0x3300, 0x21b9: 0x3300, 0x21ba: 0x3300, 0x21bb: 0x3300,
+ 0x21bc: 0x3300, 0x21bd: 0x3300, 0x21be: 0x3300, 0x21bf: 0x3300,
+ // Block 0x87, offset 0x21c0
+ 0x21c0: 0x3300, 0x21c1: 0x3300, 0x21c2: 0x3300, 0x21c3: 0x3300, 0x21c4: 0x3300, 0x21c5: 0x3300,
+ 0x21c6: 0x3300, 0x21c7: 0x3300, 0x21c8: 0x3300, 0x21c9: 0x3300, 0x21ca: 0x3300, 0x21cb: 0x3300,
+ 0x21cc: 0x3300, 0x21cd: 0x3300, 0x21d0: 0x3300,
+ 0x21d2: 0x3300, 0x21d5: 0x3300, 0x21d6: 0x3300, 0x21d7: 0x3300,
+ 0x21d8: 0x3300, 0x21d9: 0x3300, 0x21da: 0x3300, 0x21db: 0x3300, 0x21dc: 0x3300, 0x21dd: 0x3300,
+ 0x21de: 0x3300, 0x21e0: 0x3300, 0x21e2: 0x3300,
+ 0x21e5: 0x3300, 0x21e6: 0x3300,
+ 0x21ea: 0x3300, 0x21eb: 0x3300, 0x21ec: 0x3300, 0x21ed: 0x3300,
+ 0x21f0: 0x3300, 0x21f1: 0x3300, 0x21f2: 0x3300, 0x21f3: 0x3300, 0x21f4: 0x3300, 0x21f5: 0x3300,
+ 0x21f6: 0x3300, 0x21f7: 0x3300, 0x21f8: 0x3300, 0x21f9: 0x3300, 0x21fa: 0x3300, 0x21fb: 0x3300,
+ 0x21fc: 0x3300, 0x21fd: 0x3300, 0x21fe: 0x3300, 0x21ff: 0x3300,
+ // Block 0x88, offset 0x2200
+ 0x2200: 0x3300, 0x2201: 0x3300, 0x2202: 0x3300, 0x2203: 0x3300, 0x2204: 0x3300, 0x2205: 0x3300,
+ 0x2206: 0x3300, 0x2207: 0x3300, 0x2208: 0x3300, 0x2209: 0x3300, 0x220a: 0x3300, 0x220b: 0x3300,
+ 0x220c: 0x3300, 0x220d: 0x3300, 0x220e: 0x3300, 0x220f: 0x3300, 0x2210: 0x3300, 0x2211: 0x3300,
+ 0x2212: 0x3300, 0x2213: 0x3300, 0x2214: 0x3300, 0x2215: 0x3300, 0x2216: 0x3300, 0x2217: 0x3300,
+ 0x2218: 0x3300, 0x2219: 0x3300, 0x221a: 0x3300, 0x221b: 0x3300, 0x221c: 0x3300, 0x221d: 0x3300,
+ 0x221e: 0x3300, 0x221f: 0x3300, 0x2220: 0x3300, 0x2221: 0x3300, 0x2222: 0x3300, 0x2223: 0x3300,
+ 0x2224: 0x3300, 0x2225: 0x3300, 0x2226: 0x3300, 0x2227: 0x3300, 0x2228: 0x3300, 0x2229: 0x3300,
+ 0x222a: 0x3300, 0x222b: 0x3300, 0x222c: 0x3300, 0x222d: 0x3300,
+ 0x2230: 0x3300, 0x2231: 0x3300, 0x2232: 0x3300, 0x2233: 0x3300, 0x2234: 0x3300, 0x2235: 0x3300,
+ 0x2236: 0x3300, 0x2237: 0x3300, 0x2238: 0x3300, 0x2239: 0x3300, 0x223a: 0x3300, 0x223b: 0x3300,
+ 0x223c: 0x3300, 0x223d: 0x3300, 0x223e: 0x3300, 0x223f: 0x3300,
+ // Block 0x89, offset 0x2240
+ 0x2240: 0x3300, 0x2241: 0x3300, 0x2242: 0x3300, 0x2243: 0x3300, 0x2244: 0x3300, 0x2245: 0x3300,
+ 0x2246: 0x3300, 0x2247: 0x3300, 0x2248: 0x3300, 0x2249: 0x3300, 0x224a: 0x3300, 0x224b: 0x3300,
+ 0x224c: 0x3300, 0x224d: 0x3300, 0x224e: 0x3300, 0x224f: 0x3300, 0x2250: 0x3300, 0x2251: 0x3300,
+ 0x2252: 0x3300, 0x2253: 0x3300, 0x2254: 0x3300, 0x2255: 0x3300, 0x2256: 0x3300, 0x2257: 0x3300,
+ 0x2258: 0x3300, 0x2259: 0x3300,
+ // Block 0x8a, offset 0x2280
+ 0x2280: 0x3000, 0x2281: 0x3000, 0x2282: 0x3000, 0x2283: 0x3000, 0x2284: 0x3000, 0x2285: 0x3000,
+ 0x2286: 0x3000,
+ 0x2293: 0x3000, 0x2294: 0x3000, 0x2295: 0x3000, 0x2296: 0x3000, 0x2297: 0x3000,
+ 0x229d: 0x3300,
+ 0x229e: 0x001a, 0x229f: 0x3300, 0x22a0: 0x3000, 0x22a1: 0x3000, 0x22a2: 0x3000, 0x22a3: 0x3000,
+ 0x22a4: 0x3000, 0x22a5: 0x3000, 0x22a6: 0x3000, 0x22a7: 0x3000, 0x22a8: 0x3000, 0x22a9: 0x3000,
+ 0x22aa: 0x3300, 0x22ab: 0x3300, 0x22ac: 0x3300, 0x22ad: 0x3300, 0x22ae: 0x3300, 0x22af: 0x3300,
+ 0x22b0: 0x3300, 0x22b1: 0x3300, 0x22b2: 0x3300, 0x22b3: 0x3300, 0x22b4: 0x3300, 0x22b5: 0x3300,
+ 0x22b6: 0x3300, 0x22b8: 0x3300, 0x22b9: 0x3300, 0x22ba: 0x3300, 0x22bb: 0x3300,
+ 0x22bc: 0x3300, 0x22be: 0x3300,
+ // Block 0x8b, offset 0x22c0
+ 0x22c0: 0x3300, 0x22c1: 0x3300, 0x22c3: 0x3300, 0x22c4: 0x3300,
+ 0x22c6: 0x3300, 0x22c7: 0x3300, 0x22c8: 0x3300, 0x22c9: 0x3300, 0x22ca: 0x3300, 0x22cb: 0x3300,
+ 0x22cc: 0x3300, 0x22cd: 0x3300, 0x22ce: 0x3300, 0x22cf: 0x3000, 0x22d0: 0x3000, 0x22d1: 0x3000,
+ 0x22d2: 0x3000, 0x22d3: 0x3000, 0x22d4: 0x3000, 0x22d5: 0x3000, 0x22d6: 0x3000, 0x22d7: 0x3000,
+ 0x22d8: 0x3000, 0x22d9: 0x3000, 0x22da: 0x3000, 0x22db: 0x3000, 0x22dc: 0x3000, 0x22dd: 0x3000,
+ 0x22de: 0x3000, 0x22df: 0x3000, 0x22e0: 0x3000, 0x22e1: 0x3000, 0x22e2: 0x3000, 0x22e3: 0x3000,
+ 0x22e4: 0x3000, 0x22e5: 0x3000, 0x22e6: 0x3000, 0x22e7: 0x3000, 0x22e8: 0x3000, 0x22e9: 0x3000,
+ 0x22ea: 0x3000, 0x22eb: 0x3000, 0x22ec: 0x3000, 0x22ed: 0x3000, 0x22ee: 0x3000, 0x22ef: 0x3000,
+ 0x22f0: 0x3000, 0x22f1: 0x3000, 0x22f2: 0x3000, 0x22f3: 0x3000, 0x22f4: 0x3000, 0x22f5: 0x3000,
+ 0x22f6: 0x3000, 0x22f7: 0x3000, 0x22f8: 0x3000, 0x22f9: 0x3000, 0x22fa: 0x3000, 0x22fb: 0x3000,
+ 0x22fc: 0x3000, 0x22fd: 0x3000, 0x22fe: 0x3000, 0x22ff: 0x3000,
+ // Block 0x8c, offset 0x2300
+ 0x2300: 0x3000, 0x2301: 0x3000, 0x2302: 0x3000, 0x2303: 0x3000, 0x2304: 0x3000, 0x2305: 0x3000,
+ 0x2306: 0x3000, 0x2307: 0x3000, 0x2308: 0x3000, 0x2309: 0x3000, 0x230a: 0x3000, 0x230b: 0x3000,
+ 0x230c: 0x3000, 0x230d: 0x3000, 0x230e: 0x3000, 0x230f: 0x3000, 0x2310: 0x3000, 0x2311: 0x3000,
+ 0x2312: 0x3000, 0x2313: 0x3000, 0x2314: 0x3000, 0x2315: 0x3000, 0x2316: 0x3000, 0x2317: 0x3000,
+ 0x2318: 0x3000, 0x2319: 0x3000, 0x231a: 0x3000, 0x231b: 0x3000, 0x231c: 0x3000, 0x231d: 0x3000,
+ 0x231e: 0x3000, 0x231f: 0x3000, 0x2320: 0x3000, 0x2321: 0x3000, 0x2322: 0x3000, 0x2323: 0x3000,
+ 0x2324: 0x3000, 0x2325: 0x3000, 0x2326: 0x3000, 0x2327: 0x3000, 0x2328: 0x3000, 0x2329: 0x3000,
+ 0x232a: 0x3000, 0x232b: 0x3000, 0x232c: 0x3000, 0x232d: 0x3000, 0x232e: 0x3000, 0x232f: 0x3000,
+ 0x2330: 0x3000, 0x2331: 0x3000,
+ // Block 0x8d, offset 0x2340
+ 0x2353: 0x3000, 0x2354: 0x3000, 0x2355: 0x3000, 0x2356: 0x3000, 0x2357: 0x3000,
+ 0x2358: 0x3000, 0x2359: 0x3000, 0x235a: 0x3000, 0x235b: 0x3000, 0x235c: 0x3000, 0x235d: 0x3000,
+ 0x235e: 0x3000, 0x235f: 0x3000, 0x2360: 0x3000, 0x2361: 0x3000, 0x2362: 0x3000, 0x2363: 0x3000,
+ 0x2364: 0x3000, 0x2365: 0x3000, 0x2366: 0x3000, 0x2367: 0x3000, 0x2368: 0x3000, 0x2369: 0x3000,
+ 0x236a: 0x3000, 0x236b: 0x3000, 0x236c: 0x3000, 0x236d: 0x3000, 0x236e: 0x3000, 0x236f: 0x3000,
+ 0x2370: 0x3000, 0x2371: 0x3000, 0x2372: 0x3000, 0x2373: 0x3000, 0x2374: 0x3000, 0x2375: 0x3000,
+ 0x2376: 0x3000, 0x2377: 0x3000, 0x2378: 0x3000, 0x2379: 0x3000, 0x237a: 0x3000, 0x237b: 0x3000,
+ 0x237c: 0x3000, 0x237d: 0x3000, 0x237e: 0x3000, 0x237f: 0x3000,
+ // Block 0x8e, offset 0x2380
+ 0x2380: 0x3000, 0x2381: 0x3000, 0x2382: 0x3000, 0x2383: 0x3000, 0x2384: 0x3000, 0x2385: 0x3000,
+ 0x2386: 0x3000, 0x2387: 0x3000, 0x2388: 0x3000, 0x2389: 0x3000, 0x238a: 0x3000, 0x238b: 0x3000,
+ 0x238c: 0x3000, 0x238d: 0x3000, 0x238e: 0x3000, 0x238f: 0x3000, 0x2390: 0x3000, 0x2391: 0x3000,
+ 0x2392: 0x3000, 0x2393: 0x3000, 0x2394: 0x3000, 0x2395: 0x3000, 0x2396: 0x3000, 0x2397: 0x3000,
+ 0x2398: 0x3000, 0x2399: 0x3000, 0x239a: 0x3000, 0x239b: 0x3000, 0x239c: 0x3000, 0x239d: 0x3000,
+ 0x239e: 0x3000, 0x239f: 0x3000, 0x23a0: 0x3000, 0x23a1: 0x3000, 0x23a2: 0x3000, 0x23a3: 0x3000,
+ 0x23a4: 0x3000, 0x23a5: 0x3000, 0x23a6: 0x3000, 0x23a7: 0x3000, 0x23a8: 0x3000, 0x23a9: 0x3000,
+ 0x23aa: 0x3000, 0x23ab: 0x3000, 0x23ac: 0x3000, 0x23ad: 0x3000, 0x23ae: 0x3000, 0x23af: 0x3000,
+ 0x23b0: 0x3000, 0x23b1: 0x3000, 0x23b2: 0x3000, 0x23b3: 0x3000, 0x23b4: 0x3000, 0x23b5: 0x3000,
+ 0x23b6: 0x3000, 0x23b7: 0x3000, 0x23b8: 0x3000, 0x23b9: 0x3000, 0x23ba: 0x3000, 0x23bb: 0x3000,
+ 0x23bc: 0x3000, 0x23bd: 0x3000,
+ // Block 0x8f, offset 0x23c0
+ 0x23d0: 0x3000, 0x23d1: 0x3000,
+ 0x23d2: 0x3000, 0x23d3: 0x3000, 0x23d4: 0x3000, 0x23d5: 0x3000, 0x23d6: 0x3000, 0x23d7: 0x3000,
+ 0x23d8: 0x3000, 0x23d9: 0x3000, 0x23da: 0x3000, 0x23db: 0x3000, 0x23dc: 0x3000, 0x23dd: 0x3000,
+ 0x23de: 0x3000, 0x23df: 0x3000, 0x23e0: 0x3000, 0x23e1: 0x3000, 0x23e2: 0x3000, 0x23e3: 0x3000,
+ 0x23e4: 0x3000, 0x23e5: 0x3000, 0x23e6: 0x3000, 0x23e7: 0x3000, 0x23e8: 0x3000, 0x23e9: 0x3000,
+ 0x23ea: 0x3000, 0x23eb: 0x3000, 0x23ec: 0x3000, 0x23ed: 0x3000, 0x23ee: 0x3000, 0x23ef: 0x3000,
+ 0x23f0: 0x3000, 0x23f1: 0x3000, 0x23f2: 0x3000, 0x23f3: 0x3000, 0x23f4: 0x3000, 0x23f5: 0x3000,
+ 0x23f6: 0x3000, 0x23f7: 0x3000, 0x23f8: 0x3000, 0x23f9: 0x3000, 0x23fa: 0x3000, 0x23fb: 0x3000,
+ 0x23fc: 0x3000, 0x23fd: 0x3000, 0x23fe: 0x3000, 0x23ff: 0x3000,
+ // Block 0x90, offset 0x2400
+ 0x2400: 0x3000, 0x2401: 0x3000, 0x2402: 0x3000, 0x2403: 0x3000, 0x2404: 0x3000, 0x2405: 0x3000,
+ 0x2406: 0x3000, 0x2407: 0x3000, 0x2408: 0x3000, 0x2409: 0x3000, 0x240a: 0x3000, 0x240b: 0x3000,
+ 0x240c: 0x3000, 0x240d: 0x3000, 0x240e: 0x3000, 0x240f: 0x3000,
+ 0x2412: 0x3000, 0x2413: 0x3000, 0x2414: 0x3000, 0x2415: 0x3000, 0x2416: 0x3000, 0x2417: 0x3000,
+ 0x2418: 0x3000, 0x2419: 0x3000, 0x241a: 0x3000, 0x241b: 0x3000, 0x241c: 0x3000, 0x241d: 0x3000,
+ 0x241e: 0x3000, 0x241f: 0x3000, 0x2420: 0x3000, 0x2421: 0x3000, 0x2422: 0x3000, 0x2423: 0x3000,
+ 0x2424: 0x3000, 0x2425: 0x3000, 0x2426: 0x3000, 0x2427: 0x3000, 0x2428: 0x3000, 0x2429: 0x3000,
+ 0x242a: 0x3000, 0x242b: 0x3000, 0x242c: 0x3000, 0x242d: 0x3000, 0x242e: 0x3000, 0x242f: 0x3000,
+ 0x2430: 0x3000, 0x2431: 0x3000, 0x2432: 0x3000, 0x2433: 0x3000, 0x2434: 0x3000, 0x2435: 0x3000,
+ 0x2436: 0x3000, 0x2437: 0x3000, 0x2438: 0x3000, 0x2439: 0x3000, 0x243a: 0x3000, 0x243b: 0x3000,
+ 0x243c: 0x3000, 0x243d: 0x3000, 0x243e: 0x3000, 0x243f: 0x3000,
+ // Block 0x91, offset 0x2440
+ 0x2440: 0x3000, 0x2441: 0x3000, 0x2442: 0x3000, 0x2443: 0x3000, 0x2444: 0x3000, 0x2445: 0x3000,
+ 0x2446: 0x3000, 0x2447: 0x3000,
+ 0x2470: 0x3000, 0x2471: 0x3000, 0x2472: 0x3000, 0x2473: 0x3000, 0x2474: 0x3000, 0x2475: 0x3000,
+ 0x2476: 0x3000, 0x2477: 0x3000, 0x2478: 0x3000, 0x2479: 0x3000, 0x247a: 0x3000, 0x247b: 0x3000,
+ 0x247c: 0x3000,
+ // Block 0x92, offset 0x2480
+ 0x2490: 0x3000, 0x2491: 0x3000,
+ 0x2492: 0x3000, 0x2493: 0x3000, 0x2494: 0x3000, 0x2495: 0x3000, 0x2496: 0x3000, 0x2497: 0x3000,
+ 0x2498: 0x3000, 0x2499: 0x3000,
+ 0x24a0: 0x00e6, 0x24a1: 0x00e6, 0x24a2: 0x00e6, 0x24a3: 0x00e6,
+ 0x24a4: 0x00e6, 0x24a5: 0x00e6, 0x24a6: 0x00e6,
+ 0x24b0: 0x3000, 0x24b1: 0x3000, 0x24b2: 0x3000, 0x24b3: 0x3000, 0x24b4: 0x3000, 0x24b5: 0x3000,
+ 0x24b6: 0x3000, 0x24b7: 0x3000, 0x24b8: 0x3000, 0x24b9: 0x3000, 0x24ba: 0x3000, 0x24bb: 0x3000,
+ 0x24bc: 0x3000, 0x24bd: 0x3000, 0x24be: 0x3000, 0x24bf: 0x3000,
+ // Block 0x93, offset 0x24c0
+ 0x24c0: 0x3000, 0x24c1: 0x3000, 0x24c2: 0x3000, 0x24c3: 0x3000, 0x24c4: 0x3000,
+ 0x24c7: 0x3000, 0x24c8: 0x3000, 0x24c9: 0x3000, 0x24ca: 0x3000, 0x24cb: 0x3000,
+ 0x24cc: 0x3000, 0x24cd: 0x3000, 0x24ce: 0x3000, 0x24cf: 0x3000, 0x24d0: 0x3000, 0x24d1: 0x3000,
+ 0x24d2: 0x3000, 0x24d4: 0x3000, 0x24d5: 0x3000, 0x24d6: 0x3000, 0x24d7: 0x3000,
+ 0x24d8: 0x3000, 0x24d9: 0x3000, 0x24da: 0x3000, 0x24db: 0x3000, 0x24dc: 0x3000, 0x24dd: 0x3000,
+ 0x24de: 0x3000, 0x24df: 0x3000, 0x24e0: 0x3000, 0x24e1: 0x3000, 0x24e2: 0x3000, 0x24e3: 0x3000,
+ 0x24e4: 0x3000, 0x24e5: 0x3000, 0x24e6: 0x3000, 0x24e8: 0x3000, 0x24e9: 0x3000,
+ 0x24ea: 0x3000, 0x24eb: 0x3000,
+ 0x24f0: 0x3000, 0x24f1: 0x3000, 0x24f2: 0x3000, 0x24f4: 0x3000,
+ 0x24f6: 0x3000, 0x24f7: 0x3000, 0x24f8: 0x3000, 0x24f9: 0x3000, 0x24fa: 0x3000, 0x24fb: 0x3000,
+ 0x24fc: 0x3000, 0x24fd: 0x3000, 0x24fe: 0x3000, 0x24ff: 0x3000,
+ // Block 0x94, offset 0x2500
+ 0x2500: 0x3000, 0x2501: 0x3000, 0x2502: 0x3000, 0x2503: 0x3000, 0x2504: 0x3000, 0x2505: 0x3000,
+ 0x2506: 0x3000, 0x2507: 0x3000, 0x2508: 0x3000, 0x2509: 0x3000, 0x250a: 0x3000, 0x250b: 0x3000,
+ 0x250c: 0x3000, 0x250d: 0x3000, 0x250e: 0x3000, 0x250f: 0x3000, 0x2510: 0x3000, 0x2511: 0x3000,
+ 0x2512: 0x3000, 0x2513: 0x3000, 0x2514: 0x3000, 0x2515: 0x3000, 0x2516: 0x3000, 0x2517: 0x3000,
+ 0x2518: 0x3000, 0x2519: 0x3000, 0x251a: 0x3000, 0x251b: 0x3000, 0x251c: 0x3000, 0x251d: 0x3000,
+ 0x251e: 0x3000, 0x251f: 0x3000, 0x2520: 0x3000, 0x2521: 0x3000, 0x2522: 0x3000, 0x2523: 0x3000,
+ 0x2524: 0x3000, 0x2525: 0x3000, 0x2526: 0x3000, 0x2527: 0x3000, 0x2528: 0x3000, 0x2529: 0x3000,
+ 0x252a: 0x3000, 0x252b: 0x3000, 0x252c: 0x3000, 0x252d: 0x3000, 0x252e: 0x3000, 0x252f: 0x3000,
+ 0x2530: 0x3000, 0x2531: 0x3000, 0x2532: 0x3000, 0x2533: 0x3000, 0x2534: 0x3000, 0x2535: 0x3000,
+ 0x2536: 0x3000, 0x2537: 0x3000, 0x2538: 0x3000, 0x2539: 0x3000, 0x253a: 0x3000, 0x253b: 0x3000,
+ 0x253c: 0x3000,
+ // Block 0x95, offset 0x2540
+ 0x2541: 0x3000, 0x2542: 0x3000, 0x2543: 0x3000, 0x2544: 0x3000, 0x2545: 0x3000,
+ 0x2546: 0x3000, 0x2547: 0x3000, 0x2548: 0x3000, 0x2549: 0x3000, 0x254a: 0x3000, 0x254b: 0x3000,
+ 0x254c: 0x3000, 0x254d: 0x3000, 0x254e: 0x3000, 0x254f: 0x3000, 0x2550: 0x3000, 0x2551: 0x3000,
+ 0x2552: 0x3000, 0x2553: 0x3000, 0x2554: 0x3000, 0x2555: 0x3000, 0x2556: 0x3000, 0x2557: 0x3000,
+ 0x2558: 0x3000, 0x2559: 0x3000, 0x255a: 0x3000, 0x255b: 0x3000, 0x255c: 0x3000, 0x255d: 0x3000,
+ 0x255e: 0x3000, 0x255f: 0x3000, 0x2560: 0x3000, 0x2561: 0x3000, 0x2562: 0x3000, 0x2563: 0x3000,
+ 0x2564: 0x3000, 0x2565: 0x3000, 0x2566: 0x3000, 0x2567: 0x3000, 0x2568: 0x3000, 0x2569: 0x3000,
+ 0x256a: 0x3000, 0x256b: 0x3000, 0x256c: 0x3000, 0x256d: 0x3000, 0x256e: 0x3000, 0x256f: 0x3000,
+ 0x2570: 0x3000, 0x2571: 0x3000, 0x2572: 0x3000, 0x2573: 0x3000, 0x2574: 0x3000, 0x2575: 0x3000,
+ 0x2576: 0x3000, 0x2577: 0x3000, 0x2578: 0x3000, 0x2579: 0x3000, 0x257a: 0x3000, 0x257b: 0x3000,
+ 0x257c: 0x3000, 0x257d: 0x3000, 0x257e: 0x3000, 0x257f: 0x3000,
+ // Block 0x96, offset 0x2580
+ 0x2582: 0x3000, 0x2583: 0x3000, 0x2584: 0x3000, 0x2585: 0x3000,
+ 0x2586: 0x3000, 0x2587: 0x3000, 0x258a: 0x3000, 0x258b: 0x3000,
+ 0x258c: 0x3000, 0x258d: 0x3000, 0x258e: 0x3000, 0x258f: 0x3000,
+ 0x2592: 0x3000, 0x2593: 0x3000, 0x2594: 0x3000, 0x2595: 0x3000, 0x2596: 0x3000, 0x2597: 0x3000,
+ 0x259a: 0x3000, 0x259b: 0x3000, 0x259c: 0x3000,
+ 0x25a0: 0x3000, 0x25a1: 0x3000, 0x25a2: 0x3000, 0x25a3: 0x3000,
+ 0x25a4: 0x3000, 0x25a5: 0x3000, 0x25a6: 0x3000, 0x25a8: 0x3000, 0x25a9: 0x3000,
+ 0x25aa: 0x3000, 0x25ab: 0x3000, 0x25ac: 0x3000, 0x25ad: 0x3000, 0x25ae: 0x3000,
+ // Block 0x97, offset 0x25c0
+ 0x25fd: 0x00dc,
+ // Block 0x98, offset 0x2600
+ 0x260d: 0x00dc, 0x260f: 0x00e6,
+ 0x2638: 0x00e6, 0x2639: 0x0001, 0x263a: 0x00dc,
+ 0x263f: 0x0009,
+ // Block 0x99, offset 0x2640
+ 0x2659: 0x8800, 0x265a: 0x1100, 0x265b: 0x8800, 0x265c: 0x1100,
+ 0x2665: 0x8800,
+ 0x266b: 0x1100,
+ 0x2679: 0x0009, 0x267a: 0x6607,
+ // Block 0x9a, offset 0x2680
+ 0x269e: 0x3300, 0x269f: 0x3300, 0x26a0: 0x3300, 0x26a1: 0x3300, 0x26a2: 0x3300, 0x26a3: 0x3300,
+ 0x26a4: 0x3300, 0x26a5: 0x00d8, 0x26a6: 0x00d8, 0x26a7: 0x0001, 0x26a8: 0x0001, 0x26a9: 0x0001,
+ 0x26ad: 0x00e2, 0x26ae: 0x00d8, 0x26af: 0x00d8,
+ 0x26b0: 0x00d8, 0x26b1: 0x00d8, 0x26b2: 0x00d8,
+ 0x26bb: 0x00dc,
+ 0x26bc: 0x00dc, 0x26bd: 0x00dc, 0x26be: 0x00dc, 0x26bf: 0x00dc,
+ // Block 0x9b, offset 0x26c0
+ 0x26c0: 0x00dc, 0x26c1: 0x00dc, 0x26c2: 0x00dc, 0x26c5: 0x00e6,
+ 0x26c6: 0x00e6, 0x26c7: 0x00e6, 0x26c8: 0x00e6, 0x26c9: 0x00e6, 0x26ca: 0x00dc, 0x26cb: 0x00dc,
+ 0x26ea: 0x00e6, 0x26eb: 0x00e6, 0x26ec: 0x00e6, 0x26ed: 0x00e6,
+ 0x26fb: 0x3300,
+ 0x26fc: 0x3300, 0x26fd: 0x3300, 0x26fe: 0x3300, 0x26ff: 0x3300,
+ // Block 0x9c, offset 0x2700
+ 0x2700: 0x3300,
+ // Block 0x9d, offset 0x2740
+ 0x2742: 0x00e6, 0x2743: 0x00e6, 0x2744: 0x00e6,
+ // Block 0x9e, offset 0x2780
+ 0x2780: 0x3000, 0x2781: 0x3000, 0x2782: 0x3000, 0x2783: 0x3000, 0x2784: 0x3000, 0x2785: 0x3000,
+ 0x2786: 0x3000, 0x2787: 0x3000, 0x2788: 0x3000, 0x2789: 0x3000, 0x278a: 0x3000, 0x278b: 0x3000,
+ 0x278c: 0x3000, 0x278d: 0x3000, 0x278e: 0x3000, 0x278f: 0x3000, 0x2790: 0x3000, 0x2791: 0x3000,
+ 0x2792: 0x3000, 0x2793: 0x3000, 0x2794: 0x3000, 0x2796: 0x3000, 0x2797: 0x3000,
+ 0x2798: 0x3000, 0x2799: 0x3000, 0x279a: 0x3000, 0x279b: 0x3000, 0x279c: 0x3000, 0x279d: 0x3000,
+ 0x279e: 0x3000, 0x279f: 0x3000, 0x27a0: 0x3000, 0x27a1: 0x3000, 0x27a2: 0x3000, 0x27a3: 0x3000,
+ 0x27a4: 0x3000, 0x27a5: 0x3000, 0x27a6: 0x3000, 0x27a7: 0x3000, 0x27a8: 0x3000, 0x27a9: 0x3000,
+ 0x27aa: 0x3000, 0x27ab: 0x3000, 0x27ac: 0x3000, 0x27ad: 0x3000, 0x27ae: 0x3000, 0x27af: 0x3000,
+ 0x27b0: 0x3000, 0x27b1: 0x3000, 0x27b2: 0x3000, 0x27b3: 0x3000, 0x27b4: 0x3000, 0x27b5: 0x3000,
+ 0x27b6: 0x3000, 0x27b7: 0x3000, 0x27b8: 0x3000, 0x27b9: 0x3000, 0x27ba: 0x3000, 0x27bb: 0x3000,
+ 0x27bc: 0x3000, 0x27bd: 0x3000, 0x27be: 0x3000, 0x27bf: 0x3000,
+ // Block 0x9f, offset 0x27c0
+ 0x27c0: 0x3000, 0x27c1: 0x3000, 0x27c2: 0x3000, 0x27c3: 0x3000, 0x27c4: 0x3000, 0x27c5: 0x3000,
+ 0x27c6: 0x3000, 0x27c7: 0x3000, 0x27c8: 0x3000, 0x27c9: 0x3000, 0x27ca: 0x3000, 0x27cb: 0x3000,
+ 0x27cc: 0x3000, 0x27cd: 0x3000, 0x27ce: 0x3000, 0x27cf: 0x3000, 0x27d0: 0x3000, 0x27d1: 0x3000,
+ 0x27d2: 0x3000, 0x27d3: 0x3000, 0x27d4: 0x3000, 0x27d5: 0x3000, 0x27d6: 0x3000, 0x27d7: 0x3000,
+ 0x27d8: 0x3000, 0x27d9: 0x3000, 0x27da: 0x3000, 0x27db: 0x3000, 0x27dc: 0x3000,
+ 0x27de: 0x3000, 0x27df: 0x3000, 0x27e2: 0x3000,
+ 0x27e5: 0x3000, 0x27e6: 0x3000, 0x27e9: 0x3000,
+ 0x27ea: 0x3000, 0x27eb: 0x3000, 0x27ec: 0x3000, 0x27ee: 0x3000, 0x27ef: 0x3000,
+ 0x27f0: 0x3000, 0x27f1: 0x3000, 0x27f2: 0x3000, 0x27f3: 0x3000, 0x27f4: 0x3000, 0x27f5: 0x3000,
+ 0x27f6: 0x3000, 0x27f7: 0x3000, 0x27f8: 0x3000, 0x27f9: 0x3000, 0x27fb: 0x3000,
+ 0x27fd: 0x3000, 0x27fe: 0x3000, 0x27ff: 0x3000,
+ // Block 0xa0, offset 0x2800
+ 0x2800: 0x3000, 0x2801: 0x3000, 0x2802: 0x3000, 0x2803: 0x3000, 0x2805: 0x3000,
+ 0x2806: 0x3000, 0x2807: 0x3000, 0x2808: 0x3000, 0x2809: 0x3000, 0x280a: 0x3000, 0x280b: 0x3000,
+ 0x280c: 0x3000, 0x280d: 0x3000, 0x280e: 0x3000, 0x280f: 0x3000, 0x2810: 0x3000, 0x2811: 0x3000,
+ 0x2812: 0x3000, 0x2813: 0x3000, 0x2814: 0x3000, 0x2815: 0x3000, 0x2816: 0x3000, 0x2817: 0x3000,
+ 0x2818: 0x3000, 0x2819: 0x3000, 0x281a: 0x3000, 0x281b: 0x3000, 0x281c: 0x3000, 0x281d: 0x3000,
+ 0x281e: 0x3000, 0x281f: 0x3000, 0x2820: 0x3000, 0x2821: 0x3000, 0x2822: 0x3000, 0x2823: 0x3000,
+ 0x2824: 0x3000, 0x2825: 0x3000, 0x2826: 0x3000, 0x2827: 0x3000, 0x2828: 0x3000, 0x2829: 0x3000,
+ 0x282a: 0x3000, 0x282b: 0x3000, 0x282c: 0x3000, 0x282d: 0x3000, 0x282e: 0x3000, 0x282f: 0x3000,
+ 0x2830: 0x3000, 0x2831: 0x3000, 0x2832: 0x3000, 0x2833: 0x3000, 0x2834: 0x3000, 0x2835: 0x3000,
+ 0x2836: 0x3000, 0x2837: 0x3000, 0x2838: 0x3000, 0x2839: 0x3000, 0x283a: 0x3000, 0x283b: 0x3000,
+ 0x283c: 0x3000, 0x283d: 0x3000, 0x283e: 0x3000, 0x283f: 0x3000,
+ // Block 0xa1, offset 0x2840
+ 0x2840: 0x3000, 0x2841: 0x3000, 0x2842: 0x3000, 0x2843: 0x3000, 0x2844: 0x3000, 0x2845: 0x3000,
+ 0x2847: 0x3000, 0x2848: 0x3000, 0x2849: 0x3000, 0x284a: 0x3000,
+ 0x284d: 0x3000, 0x284e: 0x3000, 0x284f: 0x3000, 0x2850: 0x3000, 0x2851: 0x3000,
+ 0x2852: 0x3000, 0x2853: 0x3000, 0x2854: 0x3000, 0x2856: 0x3000, 0x2857: 0x3000,
+ 0x2858: 0x3000, 0x2859: 0x3000, 0x285a: 0x3000, 0x285b: 0x3000, 0x285c: 0x3000,
+ 0x285e: 0x3000, 0x285f: 0x3000, 0x2860: 0x3000, 0x2861: 0x3000, 0x2862: 0x3000, 0x2863: 0x3000,
+ 0x2864: 0x3000, 0x2865: 0x3000, 0x2866: 0x3000, 0x2867: 0x3000, 0x2868: 0x3000, 0x2869: 0x3000,
+ 0x286a: 0x3000, 0x286b: 0x3000, 0x286c: 0x3000, 0x286d: 0x3000, 0x286e: 0x3000, 0x286f: 0x3000,
+ 0x2870: 0x3000, 0x2871: 0x3000, 0x2872: 0x3000, 0x2873: 0x3000, 0x2874: 0x3000, 0x2875: 0x3000,
+ 0x2876: 0x3000, 0x2877: 0x3000, 0x2878: 0x3000, 0x2879: 0x3000, 0x287b: 0x3000,
+ 0x287c: 0x3000, 0x287d: 0x3000, 0x287e: 0x3000,
+ // Block 0xa2, offset 0x2880
+ 0x2880: 0x3000, 0x2881: 0x3000, 0x2882: 0x3000, 0x2883: 0x3000, 0x2884: 0x3000,
+ 0x2886: 0x3000, 0x288a: 0x3000, 0x288b: 0x3000,
+ 0x288c: 0x3000, 0x288d: 0x3000, 0x288e: 0x3000, 0x288f: 0x3000, 0x2890: 0x3000,
+ 0x2892: 0x3000, 0x2893: 0x3000, 0x2894: 0x3000, 0x2895: 0x3000, 0x2896: 0x3000, 0x2897: 0x3000,
+ 0x2898: 0x3000, 0x2899: 0x3000, 0x289a: 0x3000, 0x289b: 0x3000, 0x289c: 0x3000, 0x289d: 0x3000,
+ 0x289e: 0x3000, 0x289f: 0x3000, 0x28a0: 0x3000, 0x28a1: 0x3000, 0x28a2: 0x3000, 0x28a3: 0x3000,
+ 0x28a4: 0x3000, 0x28a5: 0x3000, 0x28a6: 0x3000, 0x28a7: 0x3000, 0x28a8: 0x3000, 0x28a9: 0x3000,
+ 0x28aa: 0x3000, 0x28ab: 0x3000, 0x28ac: 0x3000, 0x28ad: 0x3000, 0x28ae: 0x3000, 0x28af: 0x3000,
+ 0x28b0: 0x3000, 0x28b1: 0x3000, 0x28b2: 0x3000, 0x28b3: 0x3000, 0x28b4: 0x3000, 0x28b5: 0x3000,
+ 0x28b6: 0x3000, 0x28b7: 0x3000, 0x28b8: 0x3000, 0x28b9: 0x3000, 0x28ba: 0x3000, 0x28bb: 0x3000,
+ 0x28bc: 0x3000, 0x28bd: 0x3000, 0x28be: 0x3000, 0x28bf: 0x3000,
+ // Block 0xa3, offset 0x28c0
+ 0x28c0: 0x3000, 0x28c1: 0x3000, 0x28c2: 0x3000, 0x28c3: 0x3000, 0x28c4: 0x3000, 0x28c5: 0x3000,
+ 0x28c6: 0x3000, 0x28c7: 0x3000, 0x28c8: 0x3000, 0x28c9: 0x3000, 0x28ca: 0x3000, 0x28cb: 0x3000,
+ 0x28cc: 0x3000, 0x28cd: 0x3000, 0x28ce: 0x3000, 0x28cf: 0x3000, 0x28d0: 0x3000, 0x28d1: 0x3000,
+ 0x28d2: 0x3000, 0x28d3: 0x3000, 0x28d4: 0x3000, 0x28d5: 0x3000, 0x28d6: 0x3000, 0x28d7: 0x3000,
+ 0x28d8: 0x3000, 0x28d9: 0x3000, 0x28da: 0x3000, 0x28db: 0x3000, 0x28dc: 0x3000, 0x28dd: 0x3000,
+ 0x28de: 0x3000, 0x28df: 0x3000, 0x28e0: 0x3000, 0x28e1: 0x3000, 0x28e2: 0x3000, 0x28e3: 0x3000,
+ 0x28e4: 0x3000, 0x28e5: 0x3000, 0x28e8: 0x3000, 0x28e9: 0x3000,
+ 0x28ea: 0x3000, 0x28eb: 0x3000, 0x28ec: 0x3000, 0x28ed: 0x3000, 0x28ee: 0x3000, 0x28ef: 0x3000,
+ 0x28f0: 0x3000, 0x28f1: 0x3000, 0x28f2: 0x3000, 0x28f3: 0x3000, 0x28f4: 0x3000, 0x28f5: 0x3000,
+ 0x28f6: 0x3000, 0x28f7: 0x3000, 0x28f8: 0x3000, 0x28f9: 0x3000, 0x28fa: 0x3000, 0x28fb: 0x3000,
+ 0x28fc: 0x3000, 0x28fd: 0x3000, 0x28fe: 0x3000, 0x28ff: 0x3000,
+ // Block 0xa4, offset 0x2900
+ 0x2900: 0x3000, 0x2901: 0x3000, 0x2902: 0x3000, 0x2903: 0x3000, 0x2904: 0x3000, 0x2905: 0x3000,
+ 0x2906: 0x3000, 0x2907: 0x3000, 0x2908: 0x3000, 0x2909: 0x3000, 0x290a: 0x3000, 0x290b: 0x3000,
+ 0x290e: 0x3000, 0x290f: 0x3000, 0x2910: 0x3000, 0x2911: 0x3000,
+ 0x2912: 0x3000, 0x2913: 0x3000, 0x2914: 0x3000, 0x2915: 0x3000, 0x2916: 0x3000, 0x2917: 0x3000,
+ 0x2918: 0x3000, 0x2919: 0x3000, 0x291a: 0x3000, 0x291b: 0x3000, 0x291c: 0x3000, 0x291d: 0x3000,
+ 0x291e: 0x3000, 0x291f: 0x3000, 0x2920: 0x3000, 0x2921: 0x3000, 0x2922: 0x3000, 0x2923: 0x3000,
+ 0x2924: 0x3000, 0x2925: 0x3000, 0x2926: 0x3000, 0x2927: 0x3000, 0x2928: 0x3000, 0x2929: 0x3000,
+ 0x292a: 0x3000, 0x292b: 0x3000, 0x292c: 0x3000, 0x292d: 0x3000, 0x292e: 0x3000, 0x292f: 0x3000,
+ 0x2930: 0x3000, 0x2931: 0x3000, 0x2932: 0x3000, 0x2933: 0x3000, 0x2934: 0x3000, 0x2935: 0x3000,
+ 0x2936: 0x3000, 0x2937: 0x3000, 0x2938: 0x3000, 0x2939: 0x3000, 0x293a: 0x3000, 0x293b: 0x3000,
+ 0x293c: 0x3000, 0x293d: 0x3000, 0x293e: 0x3000, 0x293f: 0x3000,
+ // Block 0xa5, offset 0x2940
+ 0x2940: 0x3000, 0x2941: 0x3000, 0x2942: 0x3000, 0x2943: 0x3000, 0x2944: 0x3000, 0x2945: 0x3000,
+ 0x2946: 0x3000, 0x2947: 0x3000, 0x2948: 0x3000, 0x2949: 0x3000, 0x294a: 0x3000,
+ 0x2950: 0x3000, 0x2951: 0x3000,
+ 0x2952: 0x3000, 0x2953: 0x3000, 0x2954: 0x3000, 0x2955: 0x3000, 0x2956: 0x3000, 0x2957: 0x3000,
+ 0x2958: 0x3000, 0x2959: 0x3000, 0x295a: 0x3000, 0x295b: 0x3000, 0x295c: 0x3000, 0x295d: 0x3000,
+ 0x295e: 0x3000, 0x295f: 0x3000, 0x2960: 0x3000, 0x2961: 0x3000, 0x2962: 0x3000, 0x2963: 0x3000,
+ 0x2964: 0x3000, 0x2965: 0x3000, 0x2966: 0x3000, 0x2967: 0x3000, 0x2968: 0x3000, 0x2969: 0x3000,
+ 0x296a: 0x3000, 0x296b: 0x3000, 0x296c: 0x3000, 0x296d: 0x3000, 0x296e: 0x3000,
+ 0x2970: 0x3000, 0x2971: 0x3000, 0x2972: 0x3000, 0x2973: 0x3000, 0x2974: 0x3000, 0x2975: 0x3000,
+ 0x2976: 0x3000, 0x2977: 0x3000, 0x2978: 0x3000, 0x2979: 0x3000, 0x297a: 0x3000, 0x297b: 0x3000,
+ 0x297c: 0x3000, 0x297d: 0x3000, 0x297e: 0x3000, 0x297f: 0x3000,
+ // Block 0xa6, offset 0x2980
+ 0x2980: 0x3000, 0x2981: 0x3000, 0x2982: 0x3000, 0x2983: 0x3000, 0x2984: 0x3000, 0x2985: 0x3000,
+ 0x2986: 0x3000, 0x2987: 0x3000, 0x2988: 0x3000, 0x2989: 0x3000, 0x298a: 0x3000, 0x298b: 0x3000,
+ 0x298c: 0x3000, 0x298d: 0x3000, 0x298e: 0x3000, 0x298f: 0x3000,
+ // Block 0xa7, offset 0x29c0
+ 0x29d0: 0x3000,
+ // Block 0xa8, offset 0x2a00
+ 0x2a00: 0x3000, 0x2a01: 0x3000, 0x2a02: 0x3000,
+ 0x2a10: 0x3000, 0x2a11: 0x3000,
+ 0x2a12: 0x3000, 0x2a13: 0x3000, 0x2a14: 0x3000, 0x2a15: 0x3000, 0x2a16: 0x3000, 0x2a17: 0x3000,
+ 0x2a18: 0x3000, 0x2a19: 0x3000, 0x2a1a: 0x3000, 0x2a1b: 0x3000, 0x2a1c: 0x3000, 0x2a1d: 0x3000,
+ 0x2a1e: 0x3000, 0x2a1f: 0x3000, 0x2a20: 0x3000, 0x2a21: 0x3000, 0x2a22: 0x3000, 0x2a23: 0x3000,
+ 0x2a24: 0x3000, 0x2a25: 0x3000, 0x2a26: 0x3000, 0x2a27: 0x3000, 0x2a28: 0x3000, 0x2a29: 0x3000,
+ 0x2a2a: 0x3000, 0x2a2b: 0x3000, 0x2a2c: 0x3000, 0x2a2d: 0x3000, 0x2a2e: 0x3000, 0x2a2f: 0x3000,
+ 0x2a30: 0x3000, 0x2a31: 0x3000, 0x2a32: 0x3000, 0x2a33: 0x3000, 0x2a34: 0x3000, 0x2a35: 0x3000,
+ 0x2a36: 0x3000, 0x2a37: 0x3000, 0x2a38: 0x3000, 0x2a39: 0x3000, 0x2a3a: 0x3000,
+ // Block 0xa9, offset 0x2a40
+ 0x2a40: 0x3000, 0x2a41: 0x3000, 0x2a42: 0x3000, 0x2a43: 0x3000, 0x2a44: 0x3000, 0x2a45: 0x3000,
+ 0x2a46: 0x3000, 0x2a47: 0x3000, 0x2a48: 0x3000,
+ 0x2a50: 0x3000, 0x2a51: 0x3000,
+ // Block 0xaa, offset 0x2a80
+ 0x2a80: 0x3300, 0x2a81: 0x3300, 0x2a82: 0x3300, 0x2a83: 0x3300, 0x2a84: 0x3300, 0x2a85: 0x3300,
+ 0x2a86: 0x3300, 0x2a87: 0x3300, 0x2a88: 0x3300, 0x2a89: 0x3300, 0x2a8a: 0x3300, 0x2a8b: 0x3300,
+ 0x2a8c: 0x3300, 0x2a8d: 0x3300, 0x2a8e: 0x3300, 0x2a8f: 0x3300, 0x2a90: 0x3300, 0x2a91: 0x3300,
+ 0x2a92: 0x3300, 0x2a93: 0x3300, 0x2a94: 0x3300, 0x2a95: 0x3300, 0x2a96: 0x3300, 0x2a97: 0x3300,
+ 0x2a98: 0x3300, 0x2a99: 0x3300, 0x2a9a: 0x3300, 0x2a9b: 0x3300, 0x2a9c: 0x3300, 0x2a9d: 0x3300,
+}
+
+// charInfoLookup: 1152 bytes
+// Block 0 is the null block.
+var charInfoLookup = [1152]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x0c2: 0x03, 0x0c3: 0x04, 0x0c4: 0x05, 0x0c5: 0x06, 0x0c6: 0x07, 0x0c7: 0x08,
+ 0x0c8: 0x09, 0x0ca: 0x0a, 0x0cb: 0x0b, 0x0cc: 0x0c, 0x0cd: 0x0d, 0x0ce: 0x0e, 0x0cf: 0x0f,
+ 0x0d0: 0x10, 0x0d1: 0x11, 0x0d2: 0x12, 0x0d3: 0x13, 0x0d6: 0x14, 0x0d7: 0x15,
+ 0x0d8: 0x16, 0x0d9: 0x17, 0x0db: 0x18, 0x0dc: 0x19, 0x0dd: 0x1a, 0x0df: 0x1b,
+ 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07,
+ 0x0ea: 0x08, 0x0eb: 0x09, 0x0ec: 0x09, 0x0ed: 0x0a, 0x0ef: 0x0b,
+ 0x0f0: 0x11,
+ // Block 0x4, offset 0x100
+ 0x120: 0x1c, 0x121: 0x1d, 0x124: 0x1e, 0x125: 0x1f, 0x126: 0x20, 0x127: 0x21,
+ 0x128: 0x22, 0x129: 0x23, 0x12a: 0x24, 0x12b: 0x25, 0x12c: 0x20, 0x12d: 0x26, 0x12e: 0x27, 0x12f: 0x28,
+ 0x131: 0x29, 0x132: 0x2a, 0x133: 0x2b, 0x134: 0x2c, 0x135: 0x28, 0x137: 0x2d,
+ 0x138: 0x2e, 0x139: 0x2f, 0x13a: 0x30, 0x13b: 0x31, 0x13c: 0x32, 0x13d: 0x33, 0x13e: 0x34, 0x13f: 0x35,
+ // Block 0x5, offset 0x140
+ 0x140: 0x36, 0x142: 0x37, 0x143: 0x38, 0x145: 0x39, 0x146: 0x3a, 0x147: 0x3b,
+ 0x14d: 0x3c,
+ 0x15c: 0x3d, 0x15f: 0x3e,
+ 0x162: 0x3f, 0x164: 0x40,
+ 0x168: 0x41, 0x169: 0x42, 0x16c: 0x43, 0x16d: 0x44, 0x16e: 0x45, 0x16f: 0x46,
+ 0x170: 0x47, 0x173: 0x48, 0x174: 0x49, 0x175: 0x4a, 0x176: 0x4b, 0x177: 0x4c,
+ 0x178: 0x4d, 0x179: 0x4e, 0x17a: 0x4f, 0x17b: 0x50, 0x17c: 0x51, 0x17d: 0x52, 0x17e: 0x53, 0x17f: 0x54,
+ // Block 0x6, offset 0x180
+ 0x180: 0x55, 0x181: 0x56, 0x182: 0x57, 0x183: 0x58, 0x184: 0x59, 0x185: 0x5a, 0x186: 0x5b, 0x187: 0x5c,
+ 0x188: 0x5d, 0x189: 0x5e, 0x18a: 0x5f, 0x18b: 0x60, 0x18c: 0x61,
+ 0x191: 0x62, 0x192: 0x63, 0x193: 0x64,
+ 0x1a8: 0x65, 0x1a9: 0x66, 0x1ab: 0x67,
+ 0x1b1: 0x68, 0x1b3: 0x69, 0x1b5: 0x6a, 0x1b7: 0x6b,
+ 0x1ba: 0x6c, 0x1bb: 0x6d, 0x1bc: 0x63, 0x1bd: 0x63, 0x1be: 0x63, 0x1bf: 0x6e,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x6f, 0x1c1: 0x70, 0x1c2: 0x71, 0x1c3: 0x72, 0x1c4: 0x73, 0x1c5: 0x63, 0x1c6: 0x74,
+ 0x1c8: 0x75, 0x1c9: 0x76, 0x1ca: 0x63, 0x1cb: 0x77, 0x1cc: 0x63, 0x1cd: 0x63, 0x1ce: 0x63, 0x1cf: 0x63,
+ // Block 0x8, offset 0x200
+ 0x219: 0x78, 0x21b: 0x79, 0x21d: 0x7a,
+ 0x220: 0x7b, 0x223: 0x7c, 0x224: 0x7d, 0x225: 0x7e, 0x226: 0x7f, 0x227: 0x80,
+ 0x22a: 0x81, 0x22b: 0x82, 0x22f: 0x83,
+ 0x230: 0x84, 0x231: 0x84, 0x232: 0x84, 0x233: 0x84, 0x234: 0x84, 0x235: 0x84, 0x236: 0x84, 0x237: 0x84,
+ 0x238: 0x84, 0x239: 0x84, 0x23a: 0x84, 0x23b: 0x84, 0x23c: 0x84, 0x23d: 0x84, 0x23e: 0x84, 0x23f: 0x84,
+ // Block 0x9, offset 0x240
+ 0x240: 0x84, 0x241: 0x84, 0x242: 0x84, 0x243: 0x84, 0x244: 0x84, 0x245: 0x84, 0x246: 0x84, 0x247: 0x84,
+ 0x248: 0x84, 0x249: 0x84, 0x24a: 0x84, 0x24b: 0x84, 0x24c: 0x84, 0x24d: 0x84, 0x24e: 0x84, 0x24f: 0x84,
+ 0x250: 0x84, 0x251: 0x84, 0x252: 0x84, 0x253: 0x84, 0x254: 0x84, 0x255: 0x84, 0x256: 0x84, 0x257: 0x84,
+ 0x258: 0x84, 0x259: 0x84, 0x25a: 0x84, 0x25b: 0x84, 0x25c: 0x84, 0x25d: 0x84, 0x25e: 0x84, 0x25f: 0x84,
+ 0x260: 0x84, 0x261: 0x84, 0x262: 0x84, 0x263: 0x84, 0x264: 0x84, 0x265: 0x84, 0x266: 0x84, 0x267: 0x84,
+ 0x268: 0x84, 0x269: 0x84, 0x26a: 0x84, 0x26b: 0x84, 0x26c: 0x84, 0x26d: 0x84, 0x26e: 0x84, 0x26f: 0x84,
+ 0x270: 0x84, 0x271: 0x84, 0x272: 0x84, 0x273: 0x84, 0x274: 0x84, 0x275: 0x84, 0x276: 0x84, 0x277: 0x84,
+ 0x278: 0x84, 0x279: 0x84, 0x27a: 0x84, 0x27b: 0x84, 0x27c: 0x84, 0x27d: 0x84, 0x27e: 0x84, 0x27f: 0x84,
+ // Block 0xa, offset 0x280
+ 0x280: 0x84, 0x281: 0x84, 0x282: 0x84, 0x283: 0x84, 0x284: 0x84, 0x285: 0x84, 0x286: 0x84, 0x287: 0x84,
+ 0x288: 0x84, 0x289: 0x84, 0x28a: 0x84, 0x28b: 0x84, 0x28c: 0x84, 0x28d: 0x84, 0x28e: 0x84, 0x28f: 0x84,
+ 0x290: 0x84, 0x291: 0x84, 0x292: 0x84, 0x293: 0x84, 0x294: 0x84, 0x295: 0x84, 0x296: 0x84, 0x297: 0x84,
+ 0x298: 0x84, 0x299: 0x84, 0x29a: 0x84, 0x29b: 0x84, 0x29c: 0x84, 0x29d: 0x84, 0x29e: 0x85,
+ // Block 0xb, offset 0x2c0
+ 0x2e4: 0x86, 0x2e5: 0x86, 0x2e6: 0x86, 0x2e7: 0x86,
+ 0x2e8: 0x87, 0x2e9: 0x88, 0x2ea: 0x86, 0x2eb: 0x89, 0x2ec: 0x8a, 0x2ed: 0x8b, 0x2ee: 0x8c, 0x2ef: 0x8d,
+ 0x2f0: 0x63, 0x2f1: 0x63, 0x2f2: 0x63, 0x2f3: 0x63, 0x2f4: 0x8e, 0x2f5: 0x8f, 0x2f6: 0x90, 0x2f7: 0x91,
+ 0x2f8: 0x92, 0x2f9: 0x93, 0x2fa: 0x63, 0x2fb: 0x94, 0x2fc: 0x95, 0x2fd: 0x63, 0x2fe: 0x77, 0x2ff: 0x96,
+ // Block 0xc, offset 0x300
+ 0x307: 0x97,
+ 0x328: 0x98,
+ // Block 0xd, offset 0x340
+ 0x341: 0x7b, 0x342: 0x99,
+ // Block 0xe, offset 0x380
+ 0x385: 0x9a, 0x386: 0x9b, 0x387: 0x9c,
+ 0x389: 0x9d,
+ 0x390: 0x63, 0x391: 0x9e, 0x392: 0x9f, 0x393: 0xa0, 0x394: 0xa1, 0x395: 0xa2, 0x396: 0x63, 0x397: 0x63,
+ 0x398: 0x63, 0x399: 0x63, 0x39a: 0xa3, 0x39b: 0x63, 0x39c: 0x63, 0x39d: 0x63, 0x39e: 0x63, 0x39f: 0xa4,
+ // Block 0xf, offset 0x3c0
+ 0x3c4: 0xa5, 0x3c5: 0xa6, 0x3c6: 0xa7,
+ 0x3c8: 0xa8, 0x3c9: 0xa9,
+ // Block 0x10, offset 0x400
+ 0x420: 0x86, 0x421: 0x86, 0x422: 0x86, 0x423: 0x86, 0x424: 0x86, 0x425: 0x86, 0x426: 0x86, 0x427: 0x86,
+ 0x428: 0xaa,
+ // Block 0x11, offset 0x440
+ 0x450: 0x0c, 0x451: 0x0d,
+ 0x45d: 0x0e, 0x45f: 0x0f,
+ 0x46f: 0x10,
+}
+
+var charInfoTrie = trie{charInfoLookup[:], charInfoValues[:]}
+
+// Total size of tables: 78KB (80234 bytes)
diff --git a/libgo/go/exp/norm/trie.go b/libgo/go/exp/norm/trie.go
new file mode 100644
index 00000000000..6b654018757
--- /dev/null
+++ b/libgo/go/exp/norm/trie.go
@@ -0,0 +1,234 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+type trie struct {
+ index []uint8
+ values []uint16
+}
+
+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
+ t6 = 0xFC // 1111 1100
+ te = 0xFE // 1111 1110
+
+ maskx = 0x3F // 0011 1111
+ mask2 = 0x1F // 0001 1111
+ mask3 = 0x0F // 0000 1111
+ mask4 = 0x07 // 0000 0111
+)
+
+// lookup returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *trie) lookup(s []byte) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < tx:
+ return t.values[c0], 1
+ case c0 < t2:
+ return 0, 1
+ case c0 < t3:
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ return t.values[o], 2
+ case c0 < t4:
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ i = t.index[o]
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return 0, 2
+ }
+ o = uint16(i)<<6 + uint16(c2)&maskx
+ return t.values[o], 3
+ case c0 < t5:
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ i = t.index[o]
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return 0, 2
+ }
+ o = uint16(i)<<6 + uint16(c2)&maskx
+ i = t.index[o]
+ c3 := s[3]
+ if c3 < tx || t2 <= c3 {
+ return 0, 3
+ }
+ o = uint16(i)<<6 + uint16(c3)&maskx
+ return t.values[o], 4
+ case c0 < t6:
+ if len(s) < 5 {
+ return 0, 0
+ }
+ return 0, 5
+ case c0 < te:
+ if len(s) < 6 {
+ return 0, 0
+ }
+ return 0, 6
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupString returns the trie value for the first UTF-8 encoding in s and
+// the width in bytes of this encoding. The size will be 0 if s does not
+// hold enough bytes to complete the encoding. len(s) must be greater than 0.
+func (t *trie) lookupString(s string) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < tx:
+ return t.values[c0], 1
+ case c0 < t2:
+ return 0, 1
+ case c0 < t3:
+ if len(s) < 2 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ return t.values[o], 2
+ case c0 < t4:
+ if len(s) < 3 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ i = t.index[o]
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return 0, 2
+ }
+ o = uint16(i)<<6 + uint16(c2)&maskx
+ return t.values[o], 3
+ case c0 < t5:
+ if len(s) < 4 {
+ return 0, 0
+ }
+ i := t.index[c0]
+ c1 := s[1]
+ if c1 < tx || t2 <= c1 {
+ return 0, 1
+ }
+ o := uint16(i)<<6 + uint16(c1)&maskx
+ i = t.index[o]
+ c2 := s[2]
+ if c2 < tx || t2 <= c2 {
+ return 0, 2
+ }
+ o = uint16(i)<<6 + uint16(c2)&maskx
+ i = t.index[o]
+ c3 := s[3]
+ if c3 < tx || t2 <= c3 {
+ return 0, 3
+ }
+ o = uint16(i)<<6 + uint16(c3)&maskx
+ return t.values[o], 4
+ case c0 < t6:
+ if len(s) < 5 {
+ return 0, 0
+ }
+ return 0, 5
+ case c0 < te:
+ if len(s) < 6 {
+ return 0, 0
+ }
+ return 0, 6
+ }
+ // Illegal rune
+ return 0, 1
+}
+
+// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must hold a full encoding.
+func (t *trie) lookupUnsafe(s []byte) uint16 {
+ c0 := s[0]
+ if c0 < tx {
+ return t.values[c0]
+ }
+ if c0 < t2 {
+ return 0
+ }
+ i := t.index[c0]
+ o := uint16(i)<<6 + uint16(s[1])&maskx
+ if c0 < t3 {
+ return t.values[o]
+ }
+ i = t.index[o]
+ o = uint16(i)<<6 + uint16(s[2])&maskx
+ if c0 < t4 {
+ return t.values[o]
+ }
+ i = t.index[o]
+ o = uint16(i)<<6 + uint16(s[3])&maskx
+ if c0 < t5 {
+ return t.values[o]
+ }
+ return 0
+}
+
+// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
+// s must hold a full encoding.
+func (t *trie) lookupStringUnsafe(s string) uint16 {
+ c0 := s[0]
+ if c0 < tx {
+ return t.values[c0]
+ }
+ if c0 < t2 {
+ return 0
+ }
+ i := t.index[c0]
+ o := uint16(i)<<6 + uint16(s[1])&maskx
+ if c0 < t3 {
+ return t.values[o]
+ }
+ i = t.index[o]
+ o = uint16(i)<<6 + uint16(s[2])&maskx
+ if c0 < t4 {
+ return t.values[o]
+ }
+ i = t.index[o]
+ o = uint16(i)<<6 + uint16(s[3])&maskx
+ if c0 < t5 {
+ return t.values[o]
+ }
+ return 0
+}
diff --git a/libgo/go/exp/norm/trie_test.go b/libgo/go/exp/norm/trie_test.go
new file mode 100644
index 00000000000..ad87d972b02
--- /dev/null
+++ b/libgo/go/exp/norm/trie_test.go
@@ -0,0 +1,107 @@
+package norm
+
+import (
+ "testing"
+ "utf8"
+)
+
+// Test data is located in triedata_test.go; generated by maketesttables.
+var testdata = testdataTrie
+
+// Test cases for illegal runes.
+type trietest struct {
+ size int
+ bytes []byte
+}
+
+var tests = []trietest{
+ // illegal runes
+ {1, []byte{0x80}},
+ {1, []byte{0xFF}},
+ {1, []byte{t2, tx - 1}},
+ {1, []byte{t2, t2}},
+ {2, []byte{t3, tx, tx - 1}},
+ {2, []byte{t3, tx, t2}},
+ {1, []byte{t3, tx - 1, tx}},
+ {3, []byte{t4, tx, tx, tx - 1}},
+ {3, []byte{t4, tx, tx, t2}},
+ {1, []byte{t4, t2, tx, tx - 1}},
+ {2, []byte{t4, tx, t2, tx - 1}},
+
+ // short runes
+ {0, []byte{t2}},
+ {0, []byte{t3, tx}},
+ {0, []byte{t4, tx, tx}},
+ {0, []byte{t5, tx, tx, tx}},
+ {0, []byte{t6, tx, tx, tx, tx}},
+}
+
+func mkUtf8(rune int) ([]byte, int) {
+ var b [utf8.UTFMax]byte
+ sz := utf8.EncodeRune(b[:], rune)
+ return b[:sz], sz
+}
+
+func TestLookup(t *testing.T) {
+ for i, tt := range testRunes {
+ b, szg := mkUtf8(tt)
+ v, szt := testdata.lookup(b)
+ if int(v) != i {
+ t.Errorf("lookup(%U): found value %#x, expected %#x", i, v, i)
+ }
+ if szt != szg {
+ t.Errorf("lookup(%U): found size %d, expected %d", i, szt, szg)
+ }
+ }
+ for i, tt := range tests {
+ v, sz := testdata.lookup(tt.bytes)
+ if int(v) != 0 {
+ t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v)
+ }
+ if sz != tt.size {
+ t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size)
+ }
+ }
+}
+
+func TestLookupUnsafe(t *testing.T) {
+ for i, tt := range testRunes {
+ b, _ := mkUtf8(tt)
+ v := testdata.lookupUnsafe(b)
+ if int(v) != i {
+ t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i)
+ }
+ }
+}
+
+func TestLookupString(t *testing.T) {
+ for i, tt := range testRunes {
+ b, szg := mkUtf8(tt)
+ v, szt := testdata.lookupString(string(b))
+ if int(v) != i {
+ t.Errorf("lookup(%U): found value %#x, expected %#x", i, v, i)
+ }
+ if szt != szg {
+ t.Errorf("lookup(%U): found size %d, expected %d", i, szt, szg)
+ }
+ }
+ for i, tt := range tests {
+ v, sz := testdata.lookupString(string(tt.bytes))
+ if int(v) != 0 {
+ t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v)
+ }
+ if sz != tt.size {
+ t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size)
+ }
+ }
+}
+
+func TestLookupStringUnsafe(t *testing.T) {
+ for i, tt := range testRunes {
+ b, _ := mkUtf8(tt)
+ v := testdata.lookupStringUnsafe(string(b))
+ if int(v) != i {
+ t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i)
+ }
+ }
+}
diff --git a/libgo/go/exp/norm/triedata_test.go b/libgo/go/exp/norm/triedata_test.go
new file mode 100644
index 00000000000..f886e6004a4
--- /dev/null
+++ b/libgo/go/exp/norm/triedata_test.go
@@ -0,0 +1,63 @@
+// Generated by running
+// maketesttables
+// DO NOT EDIT
+
+package norm
+
+var testRunes = []int{1, 12, 127, 128, 256, 2047, 2048, 2457, 65535, 65536, 65793, 1114111}
+
+// testdataValues: 768 entries, 1536 bytes
+// Block 2 is the null block.
+var testdataValues = [768]uint16{
+ // Block 0x0, offset 0x0
+ 0x000c: 0x0001,
+ // Block 0x1, offset 0x40
+ 0x007f: 0x0002,
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x00c0: 0x0003,
+ // Block 0x4, offset 0x100
+ 0x0100: 0x0004,
+ // Block 0x5, offset 0x140
+ 0x017f: 0x0005,
+ // Block 0x6, offset 0x180
+ 0x0180: 0x0006,
+ // Block 0x7, offset 0x1c0
+ 0x01d9: 0x0007,
+ // Block 0x8, offset 0x200
+ 0x023f: 0x0008,
+ // Block 0x9, offset 0x240
+ 0x0240: 0x0009,
+ // Block 0xa, offset 0x280
+ 0x0281: 0x000a,
+ // Block 0xb, offset 0x2c0
+ 0x02ff: 0x000b,
+}
+
+// testdataLookup: 640 bytes
+// Block 0 is the null block.
+var testdataLookup = [640]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0x0c2: 0x03, 0x0c4: 0x04,
+ 0x0df: 0x05,
+ 0x0e0: 0x04,
+ 0x0ef: 0x05,
+ 0x0f0: 0x07, 0x0f4: 0x09,
+ // Block 0x4, offset 0x100
+ 0x120: 0x06, 0x126: 0x07,
+ // Block 0x5, offset 0x140
+ 0x17f: 0x08,
+ // Block 0x6, offset 0x180
+ 0x180: 0x09, 0x184: 0x0a,
+ // Block 0x7, offset 0x1c0
+ 0x1d0: 0x06,
+ // Block 0x8, offset 0x200
+ 0x23f: 0x0b,
+ // Block 0x9, offset 0x240
+ 0x24f: 0x08,
+}
+
+var testdataTrie = trie{testdataLookup[:], testdataValues[:]}
diff --git a/libgo/go/exp/norm/triegen.go b/libgo/go/exp/norm/triegen.go
new file mode 100644
index 00000000000..2b7eeee175b
--- /dev/null
+++ b/libgo/go/exp/norm/triegen.go
@@ -0,0 +1,211 @@
+// 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.
+
+// Trie table generator.
+// Used by make*tables tools to generate a go file with trie data structures
+// for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte
+// sequence are used to lookup offsets in the index table to be used for the
+// next byte. The last byte is used to index into a table with 16-bit values.
+
+package main
+
+import (
+ "fmt"
+ "hash/crc32"
+ "log"
+ "utf8"
+)
+
+// Intermediate trie structure
+type trieNode struct {
+ table [256]*trieNode
+ value uint16
+ b byte
+ leaf bool
+}
+
+func newNode() *trieNode {
+ return new(trieNode)
+}
+
+func (n trieNode) String() string {
+ s := fmt.Sprint("trieNode{table: { non-nil at index: ")
+ for i, v := range n.table {
+ if v != nil {
+ s += fmt.Sprintf("%d, ", i)
+ }
+ }
+ s += fmt.Sprintf("}, value:%#x, b:%#x leaf:%v}", n.value, n.b, n.leaf)
+ return s
+}
+
+func (n trieNode) isInternal() bool {
+ internal := true
+ for i := 0; i < 256; i++ {
+ if nn := n.table[i]; nn != nil {
+ if !internal && !nn.leaf {
+ log.Fatalf("triegen: isInternal: node contains both leaf and non-leaf children (%v)", n)
+ }
+ internal = internal && !nn.leaf
+ }
+ }
+ return internal
+}
+
+func (n *trieNode) insert(rune int, value uint16) {
+ var p [utf8.UTFMax]byte
+ sz := utf8.EncodeRune(p[:], rune)
+
+ for i := 0; i < sz; i++ {
+ if n.leaf {
+ log.Fatalf("triegen: insert: node (%#v) should not be a leaf", n)
+ }
+ nn := n.table[p[i]]
+ if nn == nil {
+ nn = newNode()
+ nn.b = p[i]
+ n.table[p[i]] = nn
+ }
+ n = nn
+ }
+ n.value = value
+ n.leaf = true
+}
+
+type nodeIndex struct {
+ lookupBlocks []*trieNode
+ valueBlocks []*trieNode
+
+ lookupBlockIdx map[uint32]uint16
+ valueBlockIdx map[uint32]uint16
+}
+
+func newIndex() *nodeIndex {
+ index := &nodeIndex{}
+ index.lookupBlocks = make([]*trieNode, 0)
+ index.valueBlocks = make([]*trieNode, 0)
+ index.lookupBlockIdx = make(map[uint32]uint16)
+ index.valueBlockIdx = make(map[uint32]uint16)
+ return index
+}
+
+func computeOffsets(index *nodeIndex, n *trieNode) uint16 {
+ if n.leaf {
+ return n.value
+ }
+ hasher := crc32.New(crc32.MakeTable(crc32.IEEE))
+ // We only index continuation bytes.
+ for i := 0; i < 64; i++ {
+ var v uint16 = 0
+ if nn := n.table[0x80+i]; nn != nil {
+ v = computeOffsets(index, nn)
+ }
+ hasher.Write([]byte{uint8(v >> 8), uint8(v)})
+ }
+ h := hasher.Sum32()
+ if n.isInternal() {
+ v, ok := index.lookupBlockIdx[h]
+ if !ok {
+ v = uint16(len(index.lookupBlocks))
+ index.lookupBlocks = append(index.lookupBlocks, n)
+ index.lookupBlockIdx[h] = v
+ }
+ n.value = v
+ } else {
+ v, ok := index.valueBlockIdx[h]
+ if !ok {
+ v = uint16(len(index.valueBlocks))
+ index.valueBlocks = append(index.valueBlocks, n)
+ index.valueBlockIdx[h] = v
+ }
+ n.value = v
+ }
+ return n.value
+}
+
+func printValueBlock(nr int, n *trieNode, offset int) {
+ boff := nr * 64
+ fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
+ var printnewline bool
+ for i := 0; i < 64; i++ {
+ if i%6 == 0 {
+ printnewline = true
+ }
+ v := uint16(0)
+ if nn := n.table[i+offset]; nn != nil {
+ v = nn.value
+ }
+ if v != 0 {
+ if printnewline {
+ fmt.Printf("\n")
+ printnewline = false
+ }
+ fmt.Printf("%#04x:%#04x, ", nr*64+i, v)
+ }
+ }
+}
+
+func printLookupBlock(nr int, n *trieNode, offset int) {
+ boff := nr * 64
+ fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
+ var printnewline bool
+ for i := 0; i < 64; i++ {
+ if i%8 == 0 {
+ printnewline = true
+ }
+ v := uint16(0)
+ if nn := n.table[i+offset]; nn != nil {
+ v = nn.value
+ }
+ if v != 0 {
+ if printnewline {
+ fmt.Printf("\n")
+ printnewline = false
+ }
+ fmt.Printf("%#03x:%#02x, ", boff+i, v)
+ }
+ }
+}
+
+// printTables returns the size in bytes of the generated tables.
+func (t *trieNode) printTables(name string) int {
+ index := newIndex()
+ // Values for 7-bit ASCII are stored in first two block, followed by nil block.
+ index.valueBlocks = append(index.valueBlocks, nil, nil, nil)
+ // First byte of multi-byte UTF-8 codepoints are indexed in 4th block.
+ index.lookupBlocks = append(index.lookupBlocks, nil, nil, nil, nil)
+ // Index starter bytes of multi-byte UTF-8.
+ for i := 0xC0; i < 0x100; i++ {
+ if t.table[i] != nil {
+ computeOffsets(index, t.table[i])
+ }
+ }
+
+ nv := len(index.valueBlocks) * 64
+ fmt.Printf("// %sValues: %d entries, %d bytes\n", name, nv, nv*2)
+ fmt.Printf("// Block 2 is the null block.\n")
+ fmt.Printf("var %sValues = [%d]uint16 {", name, nv)
+ printValueBlock(0, t, 0)
+ printValueBlock(1, t, 64)
+ printValueBlock(2, newNode(), 0)
+ for i := 3; i < len(index.valueBlocks); i++ {
+ printValueBlock(i, index.valueBlocks[i], 0x80)
+ }
+ fmt.Print("\n}\n\n")
+
+ ni := len(index.lookupBlocks) * 64
+ fmt.Printf("// %sLookup: %d bytes\n", name, ni)
+ fmt.Printf("// Block 0 is the null block.\n")
+ fmt.Printf("var %sLookup = [%d]uint8 {", name, ni)
+ printLookupBlock(0, newNode(), 0)
+ printLookupBlock(1, newNode(), 0)
+ printLookupBlock(2, newNode(), 0)
+ printLookupBlock(3, t, 0xC0)
+ for i := 4; i < len(index.lookupBlocks); i++ {
+ printLookupBlock(i, index.lookupBlocks[i], 0x80)
+ }
+ fmt.Print("\n}\n\n")
+ fmt.Printf("var %sTrie = trie{ %sLookup[:], %sValues[:] }\n\n", name, name, name)
+ return nv*2 + ni
+}
diff --git a/libgo/go/exp/ogle/abort.go b/libgo/go/exp/ogle/abort.go
deleted file mode 100644
index 311a7b38e24..00000000000
--- a/libgo/go/exp/ogle/abort.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 52b1c97572b..00000000000
--- a/libgo/go/exp/ogle/arch.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index a8db523ea18..00000000000
--- a/libgo/go/exp/ogle/cmd.go
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package 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.StartProcess(fname, parts, &os.ProcAttr{Files: []*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)
- 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]string
- 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
deleted file mode 100644
index d7092ded336..00000000000
--- a/libgo/go/exp/ogle/event.go
+++ /dev/null
@@ -1,280 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 1538362bad2..00000000000
--- a/libgo/go/exp/ogle/frame.go
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 5104ec6d479..00000000000
--- a/libgo/go/exp/ogle/goroutine.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 1999ecccab8..00000000000
--- a/libgo/go/exp/ogle/main.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package main
-
-import "exp/ogle"
-
-func main() { ogle.Main() }
diff --git a/libgo/go/exp/ogle/process.go b/libgo/go/exp/ogle/process.go
deleted file mode 100644
index 7c803b3a27e..00000000000
--- a/libgo/go/exp/ogle/process.go
+++ /dev/null
@@ -1,521 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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.ValueOf(&p.runtime))
- rtvt := rtv.Type()
- 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).SetUint(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
deleted file mode 100644
index 950418b5388..00000000000
--- a/libgo/go/exp/ogle/rruntime.go
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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.ValueOf(out))
- outt := outv.Type()
- runtimev := reflect.Indirect(reflect.ValueOf(runtime))
-
- // 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)
- outStructt := outStructv.Type()
- for j := 0; j < outStructt.NumField(); j++ {
- f := outStructv.Field(j)
- name := outStructt.Field(j).Name
- f.SetInt(int64(indexes[name]))
- }
- }
-}
diff --git a/libgo/go/exp/ogle/rtype.go b/libgo/go/exp/ogle/rtype.go
deleted file mode 100644
index b3c35575af4..00000000000
--- a/libgo/go/exp/ogle/rtype.go
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 3d630f93664..00000000000
--- a/libgo/go/exp/ogle/rvalue.go
+++ /dev/null
@@ -1,515 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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
deleted file mode 100644
index 8a3a14791db..00000000000
--- a/libgo/go/exp/ogle/vars.go
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package 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/exp/regexp/all_test.go b/libgo/go/exp/regexp/all_test.go
new file mode 100644
index 00000000000..77f32ca1a57
--- /dev/null
+++ b/libgo/go/exp/regexp/all_test.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 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) + "y"
+ b.StopTimer()
+ re := MustCompile("y")
+ 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", 50) + "y"
+ b.StopTimer()
+ re := MustCompile(".y")
+ 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 between '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/exp/regexp/exec.go b/libgo/go/exp/regexp/exec.go
new file mode 100644
index 00000000000..0670bb9b1b4
--- /dev/null
+++ b/libgo/go/exp/regexp/exec.go
@@ -0,0 +1,295 @@
+package regexp
+
+import "exp/regexp/syntax"
+
+// A queue is a 'sparse array' holding pending threads of execution.
+// See http://research.swtch.com/2008/03/using-uninitialized-memory-for-fun-and.html
+type queue struct {
+ sparse []uint32
+ dense []entry
+}
+
+// A entry is an entry on a queue.
+// It holds both the instruction pc and the actual thread.
+// Some queue entries are just place holders so that the machine
+// knows it has considered that pc. Such entries have t == nil.
+type entry struct {
+ pc uint32
+ t *thread
+}
+
+// A thread is the state of a single path through the machine:
+// an instruction and a corresponding capture array.
+// See http://swtch.com/~rsc/regexp/regexp2.html
+type thread struct {
+ inst *syntax.Inst
+ cap []int
+}
+
+// A machine holds all the state during an NFA simulation for p.
+type machine struct {
+ re *Regexp // corresponding Regexp
+ p *syntax.Prog // compiled program
+ q0, q1 queue // two queues for runq, nextq
+ pool []*thread // pool of available threads
+ matched bool // whether a match was found
+ matchcap []int // capture information for the match
+}
+
+// progMachine returns a new machine running the prog p.
+func progMachine(p *syntax.Prog) *machine {
+ m := &machine{p: p}
+ n := len(m.p.Inst)
+ m.q0 = queue{make([]uint32, n), make([]entry, 0, n)}
+ m.q1 = queue{make([]uint32, n), make([]entry, 0, n)}
+ ncap := p.NumCap
+ if ncap < 2 {
+ ncap = 2
+ }
+ m.matchcap = make([]int, ncap)
+ return m
+}
+
+// alloc allocates a new thread with the given instruction.
+// It uses the free pool if possible.
+func (m *machine) alloc(i *syntax.Inst) *thread {
+ var t *thread
+ if n := len(m.pool); n > 0 {
+ t = m.pool[n-1]
+ m.pool = m.pool[:n-1]
+ } else {
+ t = new(thread)
+ t.cap = make([]int, cap(m.matchcap))
+ }
+ t.cap = t.cap[:len(m.matchcap)]
+ t.inst = i
+ return t
+}
+
+// free returns t to the free pool.
+func (m *machine) free(t *thread) {
+ m.pool = append(m.pool, t)
+}
+
+// match runs the machine over the input starting at pos.
+// It reports whether a match was found.
+// If so, m.matchcap holds the submatch information.
+func (m *machine) match(i input, pos int) bool {
+ startCond := m.re.cond
+ if startCond == ^syntax.EmptyOp(0) { // impossible
+ return false
+ }
+ m.matched = false
+ for i := range m.matchcap {
+ m.matchcap[i] = -1
+ }
+ runq, nextq := &m.q0, &m.q1
+ rune, rune1 := endOfText, endOfText
+ width, width1 := 0, 0
+ rune, width = i.step(pos)
+ if rune != endOfText {
+ rune1, width1 = i.step(pos + width)
+ }
+ // TODO: Let caller specify the initial flag setting.
+ // For now assume pos == 0 is beginning of text and
+ // pos != 0 is not even beginning of line.
+ // TODO: Word boundary.
+ var flag syntax.EmptyOp
+ if pos == 0 {
+ flag = syntax.EmptyBeginText | syntax.EmptyBeginLine
+ }
+
+ // Update flag using lookahead rune.
+ if rune1 == '\n' {
+ flag |= syntax.EmptyEndLine
+ }
+ if rune1 == endOfText {
+ flag |= syntax.EmptyEndText
+ }
+
+ for {
+ if len(runq.dense) == 0 {
+ if startCond&syntax.EmptyBeginText != 0 && pos != 0 {
+ // Anchored match, past beginning of text.
+ break
+ }
+ if m.matched {
+ // Have match; finished exploring alternatives.
+ break
+ }
+ if len(m.re.prefix) > 0 && rune1 != m.re.prefixRune && i.canCheckPrefix() {
+ // Match requires literal prefix; fast search for it.
+ advance := i.index(m.re, pos)
+ if advance < 0 {
+ break
+ }
+ pos += advance
+ rune, width = i.step(pos)
+ rune1, width1 = i.step(pos + width)
+ }
+ }
+ if !m.matched {
+ if len(m.matchcap) > 0 {
+ m.matchcap[0] = pos
+ }
+ m.add(runq, uint32(m.p.Start), pos, m.matchcap, flag)
+ }
+ // TODO: word boundary
+ flag = 0
+ if rune == '\n' {
+ flag |= syntax.EmptyBeginLine
+ }
+ if rune1 == '\n' {
+ flag |= syntax.EmptyEndLine
+ }
+ if rune1 == endOfText {
+ flag |= syntax.EmptyEndText
+ }
+ m.step(runq, nextq, pos, pos+width, rune, flag)
+ if width == 0 {
+ break
+ }
+ pos += width
+ rune, width = rune1, width1
+ if rune != endOfText {
+ rune1, width1 = i.step(pos + width)
+ }
+ runq, nextq = nextq, runq
+ }
+ m.clear(nextq)
+ return m.matched
+}
+
+// clear frees all threads on the thread queue.
+func (m *machine) clear(q *queue) {
+ for _, d := range q.dense {
+ if d.t != nil {
+ m.free(d.t)
+ }
+ }
+ q.dense = q.dense[:0]
+}
+
+// step executes one step of the machine, running each of the threads
+// on runq and appending new threads to nextq.
+// The step processes the rune c (which may be endOfText),
+// which starts at position pos and ends at nextPos.
+// nextCond gives the setting for the empty-width flags after c.
+func (m *machine) step(runq, nextq *queue, pos, nextPos, c int, nextCond syntax.EmptyOp) {
+ for j := 0; j < len(runq.dense); j++ {
+ d := &runq.dense[j]
+ t := d.t
+ if t == nil {
+ continue
+ }
+ /*
+ * If we support leftmost-longest matching:
+ if longest && matched && match[0] < t.cap[0] {
+ m.free(t)
+ continue
+ }
+ */
+
+ i := t.inst
+ switch i.Op {
+ default:
+ panic("bad inst")
+
+ case syntax.InstMatch:
+ if len(t.cap) > 0 {
+ t.cap[1] = pos
+ copy(m.matchcap, t.cap)
+ }
+ m.matched = true
+ for _, d := range runq.dense[j+1:] {
+ if d.t != nil {
+ m.free(d.t)
+ }
+ }
+ runq.dense = runq.dense[:0]
+
+ case syntax.InstRune:
+ if i.MatchRune(c) {
+ m.add(nextq, i.Out, nextPos, t.cap, nextCond)
+ }
+ }
+ m.free(t)
+ }
+ runq.dense = runq.dense[:0]
+}
+
+// add adds an entry to q for pc, unless the q already has such an entry.
+// It also recursively adds an entry for all instructions reachable from pc by following
+// empty-width conditions satisfied by cond. pos gives the current position
+// in the input.
+func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.EmptyOp) {
+ if pc == 0 {
+ return
+ }
+ if j := q.sparse[pc]; j < uint32(len(q.dense)) && q.dense[j].pc == pc {
+ return
+ }
+
+ j := len(q.dense)
+ q.dense = q.dense[:j+1]
+ d := &q.dense[j]
+ d.t = nil
+ d.pc = pc
+ q.sparse[pc] = uint32(j)
+
+ i := &m.p.Inst[pc]
+ switch i.Op {
+ default:
+ panic("unhandled")
+ case syntax.InstFail:
+ // nothing
+ case syntax.InstAlt, syntax.InstAltMatch:
+ m.add(q, i.Out, pos, cap, cond)
+ m.add(q, i.Arg, pos, cap, cond)
+ case syntax.InstEmptyWidth:
+ if syntax.EmptyOp(i.Arg)&^cond == 0 {
+ m.add(q, i.Out, pos, cap, cond)
+ }
+ case syntax.InstNop:
+ m.add(q, i.Out, pos, cap, cond)
+ case syntax.InstCapture:
+ if int(i.Arg) < len(cap) {
+ opos := cap[i.Arg]
+ cap[i.Arg] = pos
+ m.add(q, i.Out, pos, cap, cond)
+ cap[i.Arg] = opos
+ } else {
+ m.add(q, i.Out, pos, cap, cond)
+ }
+ case syntax.InstMatch, syntax.InstRune:
+ t := m.alloc(i)
+ if len(t.cap) > 0 {
+ copy(t.cap, cap)
+ }
+ d.t = t
+ }
+}
+
+// empty is a non-nil 0-element slice,
+// so doExecute can avoid an allocation
+// when 0 captures are requested from a successful match.
+var empty = make([]int, 0)
+
+// doExecute finds the leftmost match in the input and returns
+// the position of its subexpressions.
+func (re *Regexp) doExecute(i input, pos int, ncap int) []int {
+ m := re.get()
+ m.matchcap = m.matchcap[:ncap]
+ if !m.match(i, pos) {
+ re.put(m)
+ return nil
+ }
+ if ncap == 0 {
+ re.put(m)
+ return empty // empty but not nil
+ }
+ cap := make([]int, ncap)
+ copy(cap, m.matchcap)
+ re.put(m)
+ return cap
+}
diff --git a/libgo/go/exp/regexp/find_test.go b/libgo/go/exp/regexp/find_test.go
new file mode 100644
index 00000000000..dddc3484c93
--- /dev/null
+++ b/libgo/go/exp/regexp/find_test.go
@@ -0,0 +1,472 @@
+// 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"
+ "strings"
+ "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\f\n\r\t\v`, "\a\f\n\r\t\v", build(1, 0, 6)},
+ {`[\a\f\n\r\t\v]+`, "\a\f\n\r\t\v", build(1, 0, 6)},
+
+ {`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)
+ }
+}
+
+func TestFindReaderIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindReaderIndex(strings.NewReader(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.Fatalf("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 TestFindStringSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
+ }
+}
+
+func TestFindReaderSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindReaderSubmatchIndex(strings.NewReader(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 TestFindAllStringSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
+ }
+}
diff --git a/libgo/go/exp/regexp/regexp.go b/libgo/go/exp/regexp/regexp.go
new file mode 100644
index 00000000000..1b75900f816
--- /dev/null
+++ b/libgo/go/exp/regexp/regexp.go
@@ -0,0 +1,795 @@
+// 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 the same
+// general syntax used by Perl, Python, and other languages.
+// More precisely, it is the syntax accepted by RE2 and described at
+// http://code.google.com/p/re2/wiki/Syntax, except for \C.
+//
+// All characters are UTF-8-encoded code points.
+//
+// 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 is also a subset of the methods that can be applied to text read
+// from a RuneReader:
+//
+// MatchReader, FindReaderIndex, FindReaderSubmatchIndex
+//
+// This set may grow. Note that regular expression matches may need to
+// examine text beyond the text returned by a match, so the methods that
+// match text from a RuneReader may read arbitrarily far into the input
+// before returning.
+//
+// (There are a few other methods that do not match this pattern.)
+//
+package regexp
+
+import (
+ "bytes"
+ "exp/regexp/syntax"
+ "io"
+ "os"
+ "strings"
+ "sync"
+ "utf8"
+)
+
+var debug = false
+
+// Error is the local type for a parsing error.
+type Error string
+
+func (e Error) String() string {
+ return string(e)
+}
+
+// Regexp is the representation of a compiled regular expression.
+// The public interface is entirely through methods.
+// A Regexp is safe for concurrent use by multiple goroutines.
+type Regexp struct {
+ // read-only after Compile
+ expr string // as passed to Compile
+ prog *syntax.Prog // compiled program
+ prefix string // required prefix in unanchored matches
+ prefixBytes []byte // prefix, as a []byte
+ prefixComplete bool // prefix is the entire regexp
+ prefixRune int // first rune in prefix
+ cond syntax.EmptyOp // empty-width conditions required at start of match
+
+ // cache of machines for running regexp
+ mu sync.Mutex
+ machine []*machine
+}
+
+// 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(expr string) (*Regexp, os.Error) {
+ re, err := syntax.Parse(expr, syntax.Perl)
+ if err != nil {
+ return nil, err
+ }
+ prog, err := syntax.Compile(re)
+ if err != nil {
+ return nil, err
+ }
+ regexp := &Regexp{
+ expr: expr,
+ prog: prog,
+ }
+ regexp.prefix, regexp.prefixComplete = prog.Prefix()
+ if regexp.prefix != "" {
+ // TODO(rsc): Remove this allocation by adding
+ // IndexString to package bytes.
+ regexp.prefixBytes = []byte(regexp.prefix)
+ regexp.prefixRune, _ = utf8.DecodeRuneInString(regexp.prefix)
+ }
+ regexp.cond = prog.StartCond()
+ return regexp, nil
+}
+
+// get returns a machine to use for matching re.
+// It uses the re's machine cache if possible, to avoid
+// unnecessary allocation.
+func (re *Regexp) get() *machine {
+ re.mu.Lock()
+ if n := len(re.machine); n > 0 {
+ z := re.machine[n-1]
+ re.machine = re.machine[:n-1]
+ re.mu.Unlock()
+ return z
+ }
+ re.mu.Unlock()
+ z := progMachine(re.prog)
+ z.re = re
+ return z
+}
+
+// put returns a machine to the re's machine cache.
+// There is no attempt to limit the size of the cache, so it will
+// grow to the maximum number of simultaneous matches
+// run using re. (The cache empties when re gets garbage collected.)
+func (re *Regexp) put(z *machine) {
+ re.mu.Lock()
+ re.machine = append(re.machine, z)
+ re.mu.Unlock()
+}
+
+// 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 {
+ // NumCap/2 because captures count ( and ) separately.
+ // -1 because NumCap counts $0 but NumSubexp does not.
+ return re.prog.NumCap/2 - 1
+}
+
+const endOfText = -1
+
+// input abstracts different representations of the input text. It provides
+// one-character lookahead.
+type input interface {
+ step(pos int) (rune int, width int) // advance one rune
+ canCheckPrefix() bool // can we look ahead without losing info?
+ hasPrefix(re *Regexp) bool
+ index(re *Regexp, pos int) int
+}
+
+// inputString scans a string.
+type inputString struct {
+ str string
+}
+
+func newInputString(str string) *inputString {
+ return &inputString{str: str}
+}
+
+func (i *inputString) step(pos int) (int, int) {
+ if pos < len(i.str) {
+ return utf8.DecodeRuneInString(i.str[pos:len(i.str)])
+ }
+ return endOfText, 0
+}
+
+func (i *inputString) canCheckPrefix() bool {
+ return true
+}
+
+func (i *inputString) hasPrefix(re *Regexp) bool {
+ return strings.HasPrefix(i.str, re.prefix)
+}
+
+func (i *inputString) index(re *Regexp, pos int) int {
+ return strings.Index(i.str[pos:], re.prefix)
+}
+
+// inputBytes scans a byte slice.
+type inputBytes struct {
+ str []byte
+}
+
+func newInputBytes(str []byte) *inputBytes {
+ return &inputBytes{str: str}
+}
+
+func (i *inputBytes) step(pos int) (int, int) {
+ if pos < len(i.str) {
+ return utf8.DecodeRune(i.str[pos:len(i.str)])
+ }
+ return endOfText, 0
+}
+
+func (i *inputBytes) canCheckPrefix() bool {
+ return true
+}
+
+func (i *inputBytes) hasPrefix(re *Regexp) bool {
+ return bytes.HasPrefix(i.str, re.prefixBytes)
+}
+
+func (i *inputBytes) index(re *Regexp, pos int) int {
+ return bytes.Index(i.str[pos:], re.prefixBytes)
+}
+
+// inputReader scans a RuneReader.
+type inputReader struct {
+ r io.RuneReader
+ atEOT bool
+ pos int
+}
+
+func newInputReader(r io.RuneReader) *inputReader {
+ return &inputReader{r: r}
+}
+
+func (i *inputReader) step(pos int) (int, int) {
+ if !i.atEOT && pos != i.pos {
+ return endOfText, 0
+
+ }
+ r, w, err := i.r.ReadRune()
+ if err != nil {
+ i.atEOT = true
+ return endOfText, 0
+ }
+ i.pos += w
+ return r, w
+}
+
+func (i *inputReader) canCheckPrefix() bool {
+ return false
+}
+
+func (i *inputReader) hasPrefix(re *Regexp) bool {
+ return false
+}
+
+func (i *inputReader) index(re *Regexp, pos int) int {
+ return -1
+}
+
+// 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) {
+ return re.prefix, re.prefixComplete
+}
+
+// MatchReader returns whether the Regexp matches the text read by the
+// RuneReader. The return value is a boolean: true for match, false for no
+// match.
+func (re *Regexp) MatchReader(r io.RuneReader) bool {
+ return re.doExecute(newInputReader(r), 0, 0) != nil
+}
+
+// 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 re.doExecute(newInputString(s), 0, 0) != nil
+}
+
+// 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 re.doExecute(newInputBytes(b), 0, 0) != nil
+}
+
+// MatchReader checks whether a textual regular expression matches the text
+// read by the RuneReader. More complicated queries need to use Compile and
+// the full Regexp interface.
+func MatchReader(pattern string, r io.RuneReader) (matched bool, error os.Error) {
+ re, err := Compile(pattern)
+ if err != nil {
+ return false, err
+ }
+ return re.MatchReader(r), nil
+}
+
+// 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(newInputString(src), searchPos, 2)
+ 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(newInputBytes(src), searchPos, 2)
+ 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()
+}
+
+var specialBytes = []byte(`\.+*?()|[]{}^$`)
+
+func special(b byte) bool {
+ return bytes.IndexByte(specialBytes, b) >= 0
+}
+
+// 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(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; {
+ var in input
+ if b == nil {
+ in = newInputString(s)
+ } else {
+ in = newInputBytes(b)
+ }
+ matches := re.doExecute(in, pos, re.prog.NumCap)
+ 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
+ // TODO: use step()
+ 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(newInputBytes(b), 0, 2)
+ 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(newInputBytes(b), 0, 2)
+ 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(newInputString(s), 0, 2)
+ 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(newInputString(s), 0, 2)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindReaderIndex returns a two-element slice of integers defining the
+// location of the leftmost match of the regular expression in text read from
+// the RuneReader. The match itself is at s[loc[0]:loc[1]]. A return
+// value of nil indicates no match.
+func (re *Regexp) FindReaderIndex(r io.RuneReader) []int {
+ a := re.doExecute(newInputReader(r), 0, 2)
+ 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(newInputBytes(b), 0, re.prog.NumCap)
+ 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(newInputBytes(b), 0, re.prog.NumCap)
+}
+
+// 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(newInputString(s), 0, re.prog.NumCap)
+ 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(newInputString(s), 0, re.prog.NumCap)
+}
+
+// FindReaderSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression of text read by
+// the RuneReader, 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) FindReaderSubmatchIndex(r io.RuneReader) []int {
+ return re.doExecute(newInputReader(r), 0, re.prog.NumCap)
+}
+
+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/exp/regexp/syntax/compile.go b/libgo/go/exp/regexp/syntax/compile.go
new file mode 100644
index 00000000000..5ea2425c3aa
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/compile.go
@@ -0,0 +1,269 @@
+package syntax
+
+import (
+ "os"
+ "unicode"
+)
+
+// A patchList is a list of instruction pointers that need to be filled in (patched).
+// Because the pointers haven't been filled in yet, we can reuse their storage
+// to hold the list. It's kind of sleazy, but works well in practice.
+// See http://swtch.com/~rsc/regexp/regexp1.html for inspiration.
+//
+// These aren't really pointers: they're integers, so we can reinterpret them
+// this way without using package unsafe. A value l denotes
+// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1).
+// l == 0 denotes the empty list, okay because we start every program
+// with a fail instruction, so we'll never want to point at its output link.
+type patchList uint32
+
+func (l patchList) next(p *Prog) patchList {
+ i := &p.Inst[l>>1]
+ if l&1 == 0 {
+ return patchList(i.Out)
+ }
+ return patchList(i.Arg)
+}
+
+func (l patchList) patch(p *Prog, val uint32) {
+ for l != 0 {
+ i := &p.Inst[l>>1]
+ if l&1 == 0 {
+ l = patchList(i.Out)
+ i.Out = val
+ } else {
+ l = patchList(i.Arg)
+ i.Arg = val
+ }
+ }
+}
+
+func (l1 patchList) append(p *Prog, l2 patchList) patchList {
+ if l1 == 0 {
+ return l2
+ }
+ if l2 == 0 {
+ return l1
+ }
+
+ last := l1
+ for {
+ next := last.next(p)
+ if next == 0 {
+ break
+ }
+ last = next
+ }
+
+ i := &p.Inst[last>>1]
+ if last&1 == 0 {
+ i.Out = uint32(l2)
+ } else {
+ i.Arg = uint32(l2)
+ }
+ return l1
+}
+
+// A frag represents a compiled program fragment.
+type frag struct {
+ i uint32 // index of first instruction
+ out patchList // where to record end instruction
+}
+
+type compiler struct {
+ p *Prog
+}
+
+// Compile compiles the regexp into a program to be executed.
+func Compile(re *Regexp) (*Prog, os.Error) {
+ var c compiler
+ c.init()
+ f := c.compile(re)
+ f.out.patch(c.p, c.inst(InstMatch).i)
+ c.p.Start = int(f.i)
+ return c.p, nil
+}
+
+func (c *compiler) init() {
+ c.p = new(Prog)
+ c.p.NumCap = 2 // implicit ( and ) for whole match $0
+ c.inst(InstFail)
+}
+
+var anyRuneNotNL = []int{0, '\n' - 1, '\n' - 1, unicode.MaxRune}
+var anyRune = []int{0, unicode.MaxRune}
+
+func (c *compiler) compile(re *Regexp) frag {
+ switch re.Op {
+ case OpNoMatch:
+ return c.fail()
+ case OpEmptyMatch:
+ return c.nop()
+ case OpLiteral:
+ if len(re.Rune) == 0 {
+ return c.nop()
+ }
+ var f frag
+ for j := range re.Rune {
+ f1 := c.rune(re.Rune[j : j+1])
+ if j == 0 {
+ f = f1
+ } else {
+ f = c.cat(f, f1)
+ }
+ }
+ return f
+ case OpCharClass:
+ return c.rune(re.Rune)
+ case OpAnyCharNotNL:
+ return c.rune(anyRuneNotNL)
+ case OpAnyChar:
+ return c.rune(anyRune)
+ case OpBeginLine:
+ return c.empty(EmptyBeginLine)
+ case OpEndLine:
+ return c.empty(EmptyEndLine)
+ case OpBeginText:
+ return c.empty(EmptyBeginText)
+ case OpEndText:
+ return c.empty(EmptyEndText)
+ case OpWordBoundary:
+ return c.empty(EmptyWordBoundary)
+ case OpNoWordBoundary:
+ return c.empty(EmptyNoWordBoundary)
+ case OpCapture:
+ bra := c.cap(uint32(re.Cap << 1))
+ sub := c.compile(re.Sub[0])
+ ket := c.cap(uint32(re.Cap<<1 | 1))
+ return c.cat(c.cat(bra, sub), ket)
+ case OpStar:
+ return c.star(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+ case OpPlus:
+ return c.plus(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+ case OpQuest:
+ return c.quest(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0)
+ case OpConcat:
+ if len(re.Sub) == 0 {
+ return c.nop()
+ }
+ var f frag
+ for i, sub := range re.Sub {
+ if i == 0 {
+ f = c.compile(sub)
+ } else {
+ f = c.cat(f, c.compile(sub))
+ }
+ }
+ return f
+ case OpAlternate:
+ var f frag
+ for _, sub := range re.Sub {
+ f = c.alt(f, c.compile(sub))
+ }
+ return f
+ }
+ panic("regexp: unhandled case in compile")
+}
+
+func (c *compiler) inst(op InstOp) frag {
+ // TODO: impose length limit
+ f := frag{i: uint32(len(c.p.Inst))}
+ c.p.Inst = append(c.p.Inst, Inst{Op: op})
+ return f
+}
+
+func (c *compiler) nop() frag {
+ f := c.inst(InstNop)
+ f.out = patchList(f.i << 1)
+ return f
+}
+
+func (c *compiler) fail() frag {
+ return frag{}
+}
+
+func (c *compiler) cap(arg uint32) frag {
+ f := c.inst(InstCapture)
+ f.out = patchList(f.i << 1)
+ c.p.Inst[f.i].Arg = arg
+
+ if c.p.NumCap < int(arg)+1 {
+ c.p.NumCap = int(arg) + 1
+ }
+ return f
+}
+
+func (c *compiler) cat(f1, f2 frag) frag {
+ // concat of failure is failure
+ if f1.i == 0 || f2.i == 0 {
+ return frag{}
+ }
+
+ // TODO: elide nop
+
+ f1.out.patch(c.p, f2.i)
+ return frag{f1.i, f2.out}
+}
+
+func (c *compiler) alt(f1, f2 frag) frag {
+ // alt of failure is other
+ if f1.i == 0 {
+ return f2
+ }
+ if f2.i == 0 {
+ return f1
+ }
+
+ f := c.inst(InstAlt)
+ i := &c.p.Inst[f.i]
+ i.Out = f1.i
+ i.Arg = f2.i
+ f.out = f1.out.append(c.p, f2.out)
+ return f
+}
+
+func (c *compiler) quest(f1 frag, nongreedy bool) frag {
+ f := c.inst(InstAlt)
+ i := &c.p.Inst[f.i]
+ if nongreedy {
+ i.Arg = f1.i
+ f.out = patchList(f.i << 1)
+ } else {
+ i.Out = f1.i
+ f.out = patchList(f.i<<1 | 1)
+ }
+ f.out = f.out.append(c.p, f1.out)
+ return f
+}
+
+func (c *compiler) star(f1 frag, nongreedy bool) frag {
+ f := c.inst(InstAlt)
+ i := &c.p.Inst[f.i]
+ if nongreedy {
+ i.Arg = f1.i
+ f.out = patchList(f.i << 1)
+ } else {
+ i.Out = f1.i
+ f.out = patchList(f.i<<1 | 1)
+ }
+ f1.out.patch(c.p, f.i)
+ return f
+}
+
+func (c *compiler) plus(f1 frag, nongreedy bool) frag {
+ return frag{f1.i, c.star(f1, nongreedy).out}
+}
+
+func (c *compiler) empty(op EmptyOp) frag {
+ f := c.inst(InstEmptyWidth)
+ c.p.Inst[f.i].Arg = uint32(op)
+ f.out = patchList(f.i << 1)
+ return f
+}
+
+func (c *compiler) rune(rune []int) frag {
+ f := c.inst(InstRune)
+ c.p.Inst[f.i].Rune = rune
+ f.out = patchList(f.i << 1)
+ return f
+}
diff --git a/libgo/go/exp/regexp/syntax/parse.go b/libgo/go/exp/regexp/syntax/parse.go
new file mode 100644
index 00000000000..4eed182687b
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/parse.go
@@ -0,0 +1,1797 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+ "os"
+ "sort"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// An Error describes a failure to parse a regular expression
+// and gives the offending expression.
+type Error struct {
+ Code ErrorCode
+ Expr string
+}
+
+func (e *Error) String() string {
+ return "error parsing regexp: " + e.Code.String() + ": `" + e.Expr + "`"
+}
+
+// An ErrorCode describes a failure to parse a regular expression.
+type ErrorCode string
+
+const (
+ // Unexpected error
+ ErrInternalError ErrorCode = "regexp/syntax: internal error"
+
+ // Parse errors
+ ErrInvalidCharClass ErrorCode = "invalid character class"
+ ErrInvalidCharRange ErrorCode = "invalid character class range"
+ ErrInvalidEscape ErrorCode = "invalid escape sequence"
+ ErrInvalidNamedCapture ErrorCode = "invalid named capture"
+ ErrInvalidPerlOp ErrorCode = "invalid or unsupported Perl syntax"
+ ErrInvalidRepeatOp ErrorCode = "invalid nested repetition operator"
+ ErrInvalidRepeatSize ErrorCode = "invalid repeat count"
+ ErrInvalidUTF8 ErrorCode = "invalid UTF-8"
+ ErrMissingBracket ErrorCode = "missing closing ]"
+ ErrMissingParen ErrorCode = "missing closing )"
+ ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator"
+ ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression"
+)
+
+func (e ErrorCode) String() string {
+ return string(e)
+}
+
+// Flags control the behavior of the parser and record information about regexp context.
+type Flags uint16
+
+const (
+ FoldCase Flags = 1 << iota // case-insensitive match
+ Literal // treat pattern as literal string
+ ClassNL // allow character classes like [^a-z] and [[:space:]] to match newline
+ DotNL // allow . to match newline
+ OneLine // treat ^ and $ as only matching at beginning and end of text
+ NonGreedy // make repetition operators default to non-greedy
+ PerlX // allow Perl extensions
+ UnicodeGroups // allow \p{Han}, \P{Han} for Unicode group and negation
+ WasDollar // regexp OpEndText was $, not \z
+ Simple // regexp contains no counted repetition
+
+ MatchNL = ClassNL | DotNL
+
+ Perl = ClassNL | OneLine | PerlX | UnicodeGroups // as close to Perl as possible
+ POSIX Flags = 0 // POSIX syntax
+)
+
+// Pseudo-ops for parsing stack.
+const (
+ opLeftParen = opPseudo + iota
+ opVerticalBar
+)
+
+type parser struct {
+ flags Flags // parse mode flags
+ stack []*Regexp // stack of parsed expressions
+ free *Regexp
+ numCap int // number of capturing groups seen
+ wholeRegexp string
+ tmpClass []int // temporary char class work space
+}
+
+func (p *parser) newRegexp(op Op) *Regexp {
+ re := p.free
+ if re != nil {
+ p.free = re.Sub0[0]
+ *re = Regexp{}
+ } else {
+ re = new(Regexp)
+ }
+ re.Op = op
+ return re
+}
+
+func (p *parser) reuse(re *Regexp) {
+ re.Sub0[0] = p.free
+ p.free = re
+}
+
+// Parse stack manipulation.
+
+// push pushes the regexp re onto the parse stack and returns the regexp.
+func (p *parser) push(re *Regexp) *Regexp {
+ if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] {
+ // Single rune.
+ if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) {
+ return nil
+ }
+ re.Op = OpLiteral
+ re.Rune = re.Rune[:1]
+ re.Flags = p.flags &^ FoldCase
+ } else if re.Op == OpCharClass && len(re.Rune) == 4 &&
+ re.Rune[0] == re.Rune[1] && re.Rune[2] == re.Rune[3] &&
+ unicode.SimpleFold(re.Rune[0]) == re.Rune[2] &&
+ unicode.SimpleFold(re.Rune[2]) == re.Rune[0] ||
+ re.Op == OpCharClass && len(re.Rune) == 2 &&
+ re.Rune[0]+1 == re.Rune[1] &&
+ unicode.SimpleFold(re.Rune[0]) == re.Rune[1] &&
+ unicode.SimpleFold(re.Rune[1]) == re.Rune[0] {
+ // Case-insensitive rune like [Aa] or [Δδ].
+ if p.maybeConcat(re.Rune[0], p.flags|FoldCase) {
+ return nil
+ }
+
+ // Rewrite as (case-insensitive) literal.
+ re.Op = OpLiteral
+ re.Rune = re.Rune[:1]
+ re.Flags = p.flags | FoldCase
+ } else {
+ // Incremental concatenation.
+ p.maybeConcat(-1, 0)
+ }
+
+ p.stack = append(p.stack, re)
+ return re
+}
+
+// maybeConcat implements incremental concatenation
+// of literal runes into string nodes. The parser calls this
+// before each push, so only the top fragment of the stack
+// might need processing. Since this is called before a push,
+// the topmost literal is no longer subject to operators like *
+// (Otherwise ab* would turn into (ab)*.)
+// If r >= 0 and there's a node left over, maybeConcat uses it
+// to push r with the given flags.
+// maybeConcat reports whether r was pushed.
+func (p *parser) maybeConcat(r int, flags Flags) bool {
+ n := len(p.stack)
+ if n < 2 {
+ return false
+ }
+
+ re1 := p.stack[n-1]
+ re2 := p.stack[n-2]
+ if re1.Op != OpLiteral || re2.Op != OpLiteral || re1.Flags&FoldCase != re2.Flags&FoldCase {
+ return false
+ }
+
+ // Push re1 into re2.
+ re2.Rune = append(re2.Rune, re1.Rune...)
+
+ // Reuse re1 if possible.
+ if r >= 0 {
+ re1.Rune = re1.Rune0[:1]
+ re1.Rune[0] = r
+ re1.Flags = flags
+ return true
+ }
+
+ p.stack = p.stack[:n-1]
+ p.reuse(re1)
+ return false // did not push r
+}
+
+// newLiteral returns a new OpLiteral Regexp with the given flags
+func (p *parser) newLiteral(r int, flags Flags) *Regexp {
+ re := p.newRegexp(OpLiteral)
+ re.Flags = flags
+ re.Rune0[0] = r
+ re.Rune = re.Rune0[:1]
+ return re
+}
+
+// literal pushes a literal regexp for the rune r on the stack
+// and returns that regexp.
+func (p *parser) literal(r int) {
+ p.push(p.newLiteral(r, p.flags))
+}
+
+// op pushes a regexp with the given op onto the stack
+// and returns that regexp.
+func (p *parser) op(op Op) *Regexp {
+ re := p.newRegexp(op)
+ re.Flags = p.flags
+ return p.push(re)
+}
+
+// repeat replaces the top stack element with itself repeated
+// according to op.
+func (p *parser) repeat(op Op, min, max int, opstr, t, lastRepeat string) (string, os.Error) {
+ flags := p.flags
+ if p.flags&PerlX != 0 {
+ if len(t) > 0 && t[0] == '?' {
+ t = t[1:]
+ flags ^= NonGreedy
+ }
+ if lastRepeat != "" {
+ // In Perl it is not allowed to stack repetition operators:
+ // a** is a syntax error, not a doubled star, and a++ means
+ // something else entirely, which we don't support!
+ return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(t)]}
+ }
+ }
+ n := len(p.stack)
+ if n == 0 {
+ return "", &Error{ErrMissingRepeatArgument, opstr}
+ }
+ sub := p.stack[n-1]
+ re := p.newRegexp(op)
+ re.Min = min
+ re.Max = max
+ re.Flags = flags
+ re.Sub = re.Sub0[:1]
+ re.Sub[0] = sub
+ p.stack[n-1] = re
+ return t, nil
+}
+
+// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
+func (p *parser) concat() *Regexp {
+ p.maybeConcat(-1, 0)
+
+ // Scan down to find pseudo-operator | or (.
+ i := len(p.stack)
+ for i > 0 && p.stack[i-1].Op < opPseudo {
+ i--
+ }
+ subs := p.stack[i:]
+ p.stack = p.stack[:i]
+
+ // Empty concatenation is special case.
+ if len(subs) == 0 {
+ return p.push(p.newRegexp(OpEmptyMatch))
+ }
+
+ return p.push(p.collapse(subs, OpConcat))
+}
+
+// alternate replaces the top of the stack (above the topmost '(') with its alternation.
+func (p *parser) alternate() *Regexp {
+ // Scan down to find pseudo-operator (.
+ // There are no | above (.
+ i := len(p.stack)
+ for i > 0 && p.stack[i-1].Op < opPseudo {
+ i--
+ }
+ subs := p.stack[i:]
+ p.stack = p.stack[:i]
+
+ // Make sure top class is clean.
+ // All the others already are (see swapVerticalBar).
+ if len(subs) > 0 {
+ cleanAlt(subs[len(subs)-1])
+ }
+
+ // Empty alternate is special case
+ // (shouldn't happen but easy to handle).
+ if len(subs) == 0 {
+ return p.push(p.newRegexp(OpNoMatch))
+ }
+
+ return p.push(p.collapse(subs, OpAlternate))
+}
+
+// cleanAlt cleans re for eventual inclusion in an alternation.
+func cleanAlt(re *Regexp) {
+ switch re.Op {
+ case OpCharClass:
+ re.Rune = cleanClass(&re.Rune)
+ if len(re.Rune) == 2 && re.Rune[0] == 0 && re.Rune[1] == unicode.MaxRune {
+ re.Rune = nil
+ re.Op = OpAnyChar
+ return
+ }
+ if len(re.Rune) == 4 && re.Rune[0] == 0 && re.Rune[1] == '\n'-1 && re.Rune[2] == '\n'+1 && re.Rune[3] == unicode.MaxRune {
+ re.Rune = nil
+ re.Op = OpAnyCharNotNL
+ return
+ }
+ if cap(re.Rune)-len(re.Rune) > 100 {
+ // re.Rune will not grow any more.
+ // Make a copy or inline to reclaim storage.
+ re.Rune = append(re.Rune0[:0], re.Rune...)
+ }
+ }
+}
+
+// collapse returns the result of applying op to sub.
+// If sub contains op nodes, they all get hoisted up
+// so that there is never a concat of a concat or an
+// alternate of an alternate.
+func (p *parser) collapse(subs []*Regexp, op Op) *Regexp {
+ if len(subs) == 1 {
+ return subs[0]
+ }
+ re := p.newRegexp(op)
+ re.Sub = re.Sub0[:0]
+ for _, sub := range subs {
+ if sub.Op == op {
+ re.Sub = append(re.Sub, sub.Sub...)
+ p.reuse(sub)
+ } else {
+ re.Sub = append(re.Sub, sub)
+ }
+ }
+ if op == OpAlternate {
+ re.Sub = p.factor(re.Sub, re.Flags)
+ if len(re.Sub) == 1 {
+ old := re
+ re = re.Sub[0]
+ p.reuse(old)
+ }
+ }
+ return re
+}
+
+// factor factors common prefixes from the alternation list sub.
+// It returns a replacement list that reuses the same storage and
+// frees (passes to p.reuse) any removed *Regexps.
+//
+// For example,
+// ABC|ABD|AEF|BCX|BCY
+// simplifies by literal prefix extraction to
+// A(B(C|D)|EF)|BC(X|Y)
+// which simplifies by character class introduction to
+// A(B[CD]|EF)|BC[XY]
+//
+func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp {
+ if len(sub) < 2 {
+ return sub
+ }
+
+ // Round 1: Factor out common literal prefixes.
+ var str []int
+ var strflags Flags
+ start := 0
+ out := sub[:0]
+ for i := 0; i <= len(sub); i++ {
+ // Invariant: the Regexps that were in sub[0:start] have been
+ // used or marked for reuse, and the slice space has been reused
+ // for out (len(out) <= start).
+ //
+ // Invariant: sub[start:i] consists of regexps that all begin
+ // with str as modified by strflags.
+ var istr []int
+ var iflags Flags
+ if i < len(sub) {
+ istr, iflags = p.leadingString(sub[i])
+ if iflags == strflags {
+ same := 0
+ for same < len(str) && same < len(istr) && str[same] == istr[same] {
+ same++
+ }
+ if same > 0 {
+ // Matches at least one rune in current range.
+ // Keep going around.
+ str = str[:same]
+ continue
+ }
+ }
+ }
+
+ // Found end of a run with common leading literal string:
+ // sub[start:i] all begin with str[0:len(str)], but sub[i]
+ // does not even begin with str[0].
+ //
+ // Factor out common string and append factored expression to out.
+ if i == start {
+ // Nothing to do - run of length 0.
+ } else if i == start+1 {
+ // Just one: don't bother factoring.
+ out = append(out, sub[start])
+ } else {
+ // Construct factored form: prefix(suffix1|suffix2|...)
+ prefix := p.newRegexp(OpLiteral)
+ prefix.Flags = strflags
+ prefix.Rune = append(prefix.Rune[:0], str...)
+
+ for j := start; j < i; j++ {
+ sub[j] = p.removeLeadingString(sub[j], len(str))
+ }
+ suffix := p.collapse(sub[start:i], OpAlternate) // recurse
+
+ re := p.newRegexp(OpConcat)
+ re.Sub = append(re.Sub[:0], prefix, suffix)
+ out = append(out, re)
+ }
+
+ // Prepare for next iteration.
+ start = i
+ str = istr
+ strflags = iflags
+ }
+ sub = out
+
+ // Round 2: Factor out common complex prefixes,
+ // just the first piece of each concatenation,
+ // whatever it is. This is good enough a lot of the time.
+ start = 0
+ out = sub[:0]
+ var first *Regexp
+ for i := 0; i <= len(sub); i++ {
+ // Invariant: the Regexps that were in sub[0:start] have been
+ // used or marked for reuse, and the slice space has been reused
+ // for out (len(out) <= start).
+ //
+ // Invariant: sub[start:i] consists of regexps that all begin
+ // with str as modified by strflags.
+ var ifirst *Regexp
+ if i < len(sub) {
+ ifirst = p.leadingRegexp(sub[i])
+ if first != nil && first.Equal(ifirst) {
+ continue
+ }
+ }
+
+ // Found end of a run with common leading regexp:
+ // sub[start:i] all begin with first but sub[i] does not.
+ //
+ // Factor out common regexp and append factored expression to out.
+ if i == start {
+ // Nothing to do - run of length 0.
+ } else if i == start+1 {
+ // Just one: don't bother factoring.
+ out = append(out, sub[start])
+ } else {
+ // Construct factored form: prefix(suffix1|suffix2|...)
+ prefix := first
+
+ for j := start; j < i; j++ {
+ reuse := j != start // prefix came from sub[start]
+ sub[j] = p.removeLeadingRegexp(sub[j], reuse)
+ }
+ suffix := p.collapse(sub[start:i], OpAlternate) // recurse
+
+ re := p.newRegexp(OpConcat)
+ re.Sub = append(re.Sub[:0], prefix, suffix)
+ out = append(out, re)
+ }
+
+ // Prepare for next iteration.
+ start = i
+ first = ifirst
+ }
+ sub = out
+
+ // Round 3: Collapse runs of single literals into character classes.
+ start = 0
+ out = sub[:0]
+ for i := 0; i <= len(sub); i++ {
+ // Invariant: the Regexps that were in sub[0:start] have been
+ // used or marked for reuse, and the slice space has been reused
+ // for out (len(out) <= start).
+ //
+ // Invariant: sub[start:i] consists of regexps that are either
+ // literal runes or character classes.
+ if i < len(sub) && isCharClass(sub[i]) {
+ continue
+ }
+
+ // sub[i] is not a char or char class;
+ // emit char class for sub[start:i]...
+ if i == start {
+ // Nothing to do - run of length 0.
+ } else if i == start+1 {
+ out = append(out, sub[start])
+ } else {
+ // Make new char class.
+ // Start with most complex regexp in sub[start].
+ max := start
+ for j := start + 1; j < i; j++ {
+ if sub[max].Op < sub[j].Op || sub[max].Op == sub[j].Op && len(sub[max].Rune) < len(sub[j].Rune) {
+ max = j
+ }
+ }
+ sub[start], sub[max] = sub[max], sub[start]
+
+ for j := start + 1; j < i; j++ {
+ mergeCharClass(sub[start], sub[j])
+ p.reuse(sub[j])
+ }
+ cleanAlt(sub[start])
+ out = append(out, sub[start])
+ }
+
+ // ... and then emit sub[i].
+ if i < len(sub) {
+ out = append(out, sub[i])
+ }
+ start = i + 1
+ }
+ sub = out
+
+ // Round 4: Collapse runs of empty matches into a single empty match.
+ start = 0
+ out = sub[:0]
+ for i := range sub {
+ if i+1 < len(sub) && sub[i].Op == OpEmptyMatch && sub[i+1].Op == OpEmptyMatch {
+ continue
+ }
+ out = append(out, sub[i])
+ }
+ sub = out
+
+ return sub
+}
+
+// leadingString returns the leading literal string that re begins with.
+// The string refers to storage in re or its children.
+func (p *parser) leadingString(re *Regexp) ([]int, Flags) {
+ if re.Op == OpConcat && len(re.Sub) > 0 {
+ re = re.Sub[0]
+ }
+ if re.Op != OpLiteral {
+ return nil, 0
+ }
+ return re.Rune, re.Flags & FoldCase
+}
+
+// removeLeadingString removes the first n leading runes
+// from the beginning of re. It returns the replacement for re.
+func (p *parser) removeLeadingString(re *Regexp, n int) *Regexp {
+ if re.Op == OpConcat && len(re.Sub) > 0 {
+ // Removing a leading string in a concatenation
+ // might simplify the concatenation.
+ sub := re.Sub[0]
+ sub = p.removeLeadingString(sub, n)
+ re.Sub[0] = sub
+ if sub.Op == OpEmptyMatch {
+ p.reuse(sub)
+ switch len(re.Sub) {
+ case 0, 1:
+ // Impossible but handle.
+ re.Op = OpEmptyMatch
+ re.Sub = nil
+ case 2:
+ old := re
+ re = re.Sub[1]
+ p.reuse(old)
+ default:
+ copy(re.Sub, re.Sub[1:])
+ re.Sub = re.Sub[:len(re.Sub)-1]
+ }
+ }
+ return re
+ }
+
+ if re.Op == OpLiteral {
+ re.Rune = re.Rune[:copy(re.Rune, re.Rune[n:])]
+ if len(re.Rune) == 0 {
+ re.Op = OpEmptyMatch
+ }
+ }
+ return re
+}
+
+// leadingRegexp returns the leading regexp that re begins with.
+// The regexp refers to storage in re or its children.
+func (p *parser) leadingRegexp(re *Regexp) *Regexp {
+ if re.Op == OpEmptyMatch {
+ return nil
+ }
+ if re.Op == OpConcat && len(re.Sub) > 0 {
+ sub := re.Sub[0]
+ if sub.Op == OpEmptyMatch {
+ return nil
+ }
+ return sub
+ }
+ return re
+}
+
+// removeLeadingRegexp removes the leading regexp in re.
+// It returns the replacement for re.
+// If reuse is true, it passes the removed regexp (if no longer needed) to p.reuse.
+func (p *parser) removeLeadingRegexp(re *Regexp, reuse bool) *Regexp {
+ if re.Op == OpConcat && len(re.Sub) > 0 {
+ if reuse {
+ p.reuse(re.Sub[0])
+ }
+ re.Sub = re.Sub[:copy(re.Sub, re.Sub[1:])]
+ switch len(re.Sub) {
+ case 0:
+ re.Op = OpEmptyMatch
+ re.Sub = nil
+ case 1:
+ old := re
+ re = re.Sub[0]
+ p.reuse(old)
+ }
+ return re
+ }
+ re.Op = OpEmptyMatch
+ return re
+}
+
+func literalRegexp(s string, flags Flags) *Regexp {
+ re := &Regexp{Op: OpLiteral}
+ re.Flags = flags
+ re.Rune = re.Rune0[:0] // use local storage for small strings
+ for _, c := range s {
+ if len(re.Rune) >= cap(re.Rune) {
+ // string is too long to fit in Rune0. let Go handle it
+ re.Rune = []int(s)
+ break
+ }
+ re.Rune = append(re.Rune, c)
+ }
+ return re
+}
+
+// Parsing.
+
+func Parse(s string, flags Flags) (*Regexp, os.Error) {
+ if flags&Literal != 0 {
+ // Trivial parser for literal string.
+ if err := checkUTF8(s); err != nil {
+ return nil, err
+ }
+ return literalRegexp(s, flags), nil
+ }
+
+ // Otherwise, must do real work.
+ var (
+ p parser
+ err os.Error
+ c int
+ op Op
+ lastRepeat string
+ min, max int
+ )
+ p.flags = flags
+ p.wholeRegexp = s
+ t := s
+ for t != "" {
+ repeat := ""
+ BigSwitch:
+ switch t[0] {
+ default:
+ if c, t, err = nextRune(t); err != nil {
+ return nil, err
+ }
+ p.literal(c)
+
+ case '(':
+ if p.flags&PerlX != 0 && len(t) >= 2 && t[1] == '?' {
+ // Flag changes and non-capturing groups.
+ if t, err = p.parsePerlFlags(t); err != nil {
+ return nil, err
+ }
+ break
+ }
+ p.numCap++
+ p.op(opLeftParen).Cap = p.numCap
+ t = t[1:]
+ case '|':
+ if err = p.parseVerticalBar(); err != nil {
+ return nil, err
+ }
+ t = t[1:]
+ case ')':
+ if err = p.parseRightParen(); err != nil {
+ return nil, err
+ }
+ t = t[1:]
+ case '^':
+ if p.flags&OneLine != 0 {
+ p.op(OpBeginText)
+ } else {
+ p.op(OpBeginLine)
+ }
+ t = t[1:]
+ case '$':
+ if p.flags&OneLine != 0 {
+ p.op(OpEndText).Flags |= WasDollar
+ } else {
+ p.op(OpEndLine)
+ }
+ t = t[1:]
+ case '.':
+ if p.flags&DotNL != 0 {
+ p.op(OpAnyChar)
+ } else {
+ p.op(OpAnyCharNotNL)
+ }
+ t = t[1:]
+ case '[':
+ if t, err = p.parseClass(t); err != nil {
+ return nil, err
+ }
+ case '*', '+', '?':
+ switch t[0] {
+ case '*':
+ op = OpStar
+ case '+':
+ op = OpPlus
+ case '?':
+ op = OpQuest
+ }
+ if t, err = p.repeat(op, min, max, t[:1], t[1:], lastRepeat); err != nil {
+ return nil, err
+ }
+ case '{':
+ op = OpRepeat
+ min, max, tt, ok := p.parseRepeat(t)
+ if !ok {
+ // If the repeat cannot be parsed, { is a literal.
+ p.literal('{')
+ t = t[1:]
+ break
+ }
+ if t, err = p.repeat(op, min, max, t[:len(t)-len(tt)], tt, lastRepeat); err != nil {
+ return nil, err
+ }
+ case '\\':
+ if p.flags&PerlX != 0 && len(t) >= 2 {
+ switch t[1] {
+ case 'A':
+ p.op(OpBeginText)
+ t = t[2:]
+ break BigSwitch
+ case 'b':
+ p.op(OpWordBoundary)
+ t = t[2:]
+ break BigSwitch
+ case 'B':
+ p.op(OpNoWordBoundary)
+ t = t[2:]
+ break BigSwitch
+ case 'C':
+ // any byte; not supported
+ return nil, &Error{ErrInvalidEscape, t[:2]}
+ case 'Q':
+ // \Q ... \E: the ... is always literals
+ var lit string
+ if i := strings.Index(t, `\E`); i < 0 {
+ lit = t[2:]
+ t = ""
+ } else {
+ lit = t[2:i]
+ t = t[i+2:]
+ }
+ p.push(literalRegexp(lit, p.flags))
+ break BigSwitch
+ case 'z':
+ p.op(OpEndText)
+ t = t[2:]
+ break BigSwitch
+ }
+ }
+
+ re := p.newRegexp(OpCharClass)
+ re.Flags = p.flags
+
+ // Look for Unicode character group like \p{Han}
+ if len(t) >= 2 && (t[1] == 'p' || t[1] == 'P') {
+ r, rest, err := p.parseUnicodeClass(t, re.Rune0[:0])
+ if err != nil {
+ return nil, err
+ }
+ if r != nil {
+ re.Rune = r
+ t = rest
+ p.push(re)
+ break BigSwitch
+ }
+ }
+
+ // Perl character class escape.
+ if r, rest := p.parsePerlClassEscape(t, re.Rune0[:0]); r != nil {
+ re.Rune = r
+ t = rest
+ p.push(re)
+ break BigSwitch
+ }
+ p.reuse(re)
+
+ // Ordinary single-character escape.
+ if c, t, err = p.parseEscape(t); err != nil {
+ return nil, err
+ }
+ p.literal(c)
+ }
+ lastRepeat = repeat
+ }
+
+ p.concat()
+ if p.swapVerticalBar() {
+ // pop vertical bar
+ p.stack = p.stack[:len(p.stack)-1]
+ }
+ p.alternate()
+
+ n := len(p.stack)
+ if n != 1 {
+ return nil, &Error{ErrMissingParen, s}
+ }
+ return p.stack[0], nil
+}
+
+// parseRepeat parses {min} (max=min) or {min,} (max=-1) or {min,max}.
+// If s is not of that form, it returns ok == false.
+func (p *parser) parseRepeat(s string) (min, max int, rest string, ok bool) {
+ if s == "" || s[0] != '{' {
+ return
+ }
+ s = s[1:]
+ if min, s, ok = p.parseInt(s); !ok {
+ return
+ }
+ if s == "" {
+ return
+ }
+ if s[0] != ',' {
+ max = min
+ } else {
+ s = s[1:]
+ if s == "" {
+ return
+ }
+ if s[0] == '}' {
+ max = -1
+ } else if max, s, ok = p.parseInt(s); !ok {
+ return
+ }
+ }
+ if s == "" || s[0] != '}' {
+ return
+ }
+ rest = s[1:]
+ ok = true
+ return
+}
+
+// parsePerlFlags parses a Perl flag setting or non-capturing group or both,
+// like (?i) or (?: or (?i:. It removes the prefix from s and updates the parse state.
+// The caller must have ensured that s begins with "(?".
+func (p *parser) parsePerlFlags(s string) (rest string, err os.Error) {
+ t := s
+
+ // Check for named captures, first introduced in Python's regexp library.
+ // As usual, there are three slightly different syntaxes:
+ //
+ // (?P<name>expr) the original, introduced by Python
+ // (?<name>expr) the .NET alteration, adopted by Perl 5.10
+ // (?'name'expr) another .NET alteration, adopted by Perl 5.10
+ //
+ // Perl 5.10 gave in and implemented the Python version too,
+ // but they claim that the last two are the preferred forms.
+ // PCRE and languages based on it (specifically, PHP and Ruby)
+ // support all three as well. EcmaScript 4 uses only the Python form.
+ //
+ // In both the open source world (via Code Search) and the
+ // Google source tree, (?P<expr>name) is the dominant form,
+ // so that's the one we implement. One is enough.
+ if len(t) > 4 && t[2] == 'P' && t[3] == '<' {
+ // Pull out name.
+ end := strings.IndexRune(t, '>')
+ if end < 0 {
+ if err = checkUTF8(t); err != nil {
+ return "", err
+ }
+ return "", &Error{ErrInvalidNamedCapture, s}
+ }
+
+ capture := t[:end+1] // "(?P<name>"
+ name := t[4:end] // "name"
+ if err = checkUTF8(name); err != nil {
+ return "", err
+ }
+ if !isValidCaptureName(name) {
+ return "", &Error{ErrInvalidNamedCapture, capture}
+ }
+
+ // Like ordinary capture, but named.
+ p.numCap++
+ re := p.op(opLeftParen)
+ re.Cap = p.numCap
+ re.Name = name
+ return t[end+1:], nil
+ }
+
+ // Non-capturing group. Might also twiddle Perl flags.
+ var c int
+ t = t[2:] // skip (?
+ flags := p.flags
+ sign := +1
+ sawFlag := false
+Loop:
+ for t != "" {
+ if c, t, err = nextRune(t); err != nil {
+ return "", err
+ }
+ switch c {
+ default:
+ break Loop
+
+ // Flags.
+ case 'i':
+ flags |= FoldCase
+ sawFlag = true
+ case 'm':
+ flags &^= OneLine
+ sawFlag = true
+ case 's':
+ flags |= DotNL
+ sawFlag = true
+ case 'U':
+ flags |= NonGreedy
+ sawFlag = true
+
+ // Switch to negation.
+ case '-':
+ if sign < 0 {
+ break Loop
+ }
+ sign = -1
+ // Invert flags so that | above turn into &^ and vice versa.
+ // We'll invert flags again before using it below.
+ flags = ^flags
+ sawFlag = false
+
+ // End of flags, starting group or not.
+ case ':', ')':
+ if sign < 0 {
+ if !sawFlag {
+ break Loop
+ }
+ flags = ^flags
+ }
+ if c == ':' {
+ // Open new group
+ p.op(opLeftParen)
+ }
+ p.flags = flags
+ return t, nil
+ }
+ }
+
+ return "", &Error{ErrInvalidPerlOp, s[:len(s)-len(t)]}
+}
+
+// isValidCaptureName reports whether name
+// is a valid capture name: [A-Za-z0-9_]+.
+// PCRE limits names to 32 bytes.
+// Python rejects names starting with digits.
+// We don't enforce either of those.
+func isValidCaptureName(name string) bool {
+ if name == "" {
+ return false
+ }
+ for _, c := range name {
+ if c != '_' && !isalnum(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// parseInt parses a decimal integer.
+func (p *parser) parseInt(s string) (n int, rest string, ok bool) {
+ if s == "" || s[0] < '0' || '9' < s[0] {
+ return
+ }
+ // Disallow leading zeros.
+ if len(s) >= 2 && s[0] == '0' && '0' <= s[1] && s[1] <= '9' {
+ return
+ }
+ for s != "" && '0' <= s[0] && s[0] <= '9' {
+ // Avoid overflow.
+ if n >= 1e8 {
+ return
+ }
+ n = n*10 + int(s[0]) - '0'
+ s = s[1:]
+ }
+ rest = s
+ ok = true
+ return
+}
+
+// can this be represented as a character class?
+// single-rune literal string, char class, ., and .|\n.
+func isCharClass(re *Regexp) bool {
+ return re.Op == OpLiteral && len(re.Rune) == 1 ||
+ re.Op == OpCharClass ||
+ re.Op == OpAnyCharNotNL ||
+ re.Op == OpAnyChar
+}
+
+// does re match r?
+func matchRune(re *Regexp, r int) bool {
+ switch re.Op {
+ case OpLiteral:
+ return len(re.Rune) == 1 && re.Rune[0] == r
+ case OpCharClass:
+ for i := 0; i < len(re.Rune); i += 2 {
+ if re.Rune[i] <= r && r <= re.Rune[i+1] {
+ return true
+ }
+ }
+ return false
+ case OpAnyCharNotNL:
+ return r != '\n'
+ case OpAnyChar:
+ return true
+ }
+ return false
+}
+
+// parseVerticalBar handles a | in the input.
+func (p *parser) parseVerticalBar() os.Error {
+ p.concat()
+
+ // The concatenation we just parsed is on top of the stack.
+ // If it sits above an opVerticalBar, swap it below
+ // (things below an opVerticalBar become an alternation).
+ // Otherwise, push a new vertical bar.
+ if !p.swapVerticalBar() {
+ p.op(opVerticalBar)
+ }
+
+ return nil
+}
+
+// mergeCharClass makes dst = dst|src.
+// The caller must ensure that dst.Op >= src.Op,
+// to reduce the amount of copying.
+func mergeCharClass(dst, src *Regexp) {
+ switch dst.Op {
+ case OpAnyChar:
+ // src doesn't add anything.
+ case OpAnyCharNotNL:
+ // src might add \n
+ if matchRune(src, '\n') {
+ dst.Op = OpAnyChar
+ }
+ case OpCharClass:
+ // src is simpler, so either literal or char class
+ if src.Op == OpLiteral {
+ dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0])
+ } else {
+ dst.Rune = appendClass(dst.Rune, src.Rune)
+ }
+ case OpLiteral:
+ // both literal
+ if src.Rune[0] == dst.Rune[0] {
+ break
+ }
+ dst.Op = OpCharClass
+ dst.Rune = append(dst.Rune, dst.Rune[0])
+ dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0])
+ }
+}
+
+// If the top of the stack is an element followed by an opVerticalBar
+// swapVerticalBar swaps the two and returns true.
+// Otherwise it returns false.
+func (p *parser) swapVerticalBar() bool {
+ // If above and below vertical bar are literal or char class,
+ // can merge into a single char class.
+ n := len(p.stack)
+ if n >= 3 && p.stack[n-2].Op == opVerticalBar && isCharClass(p.stack[n-1]) && isCharClass(p.stack[n-3]) {
+ re1 := p.stack[n-1]
+ re3 := p.stack[n-3]
+ // Make re3 the more complex of the two.
+ if re1.Op > re3.Op {
+ re1, re3 = re3, re1
+ p.stack[n-3] = re3
+ }
+ mergeCharClass(re3, re1)
+ p.reuse(re1)
+ p.stack = p.stack[:n-1]
+ return true
+ }
+
+ if n >= 2 {
+ re1 := p.stack[n-1]
+ re2 := p.stack[n-2]
+ if re2.Op == opVerticalBar {
+ if n >= 3 {
+ // Now out of reach.
+ // Clean opportunistically.
+ cleanAlt(p.stack[n-3])
+ }
+ p.stack[n-2] = re1
+ p.stack[n-1] = re2
+ return true
+ }
+ }
+ return false
+}
+
+// parseRightParen handles a ) in the input.
+func (p *parser) parseRightParen() os.Error {
+ p.concat()
+ if p.swapVerticalBar() {
+ // pop vertical bar
+ p.stack = p.stack[:len(p.stack)-1]
+ }
+ p.alternate()
+
+ n := len(p.stack)
+ if n < 2 {
+ return &Error{ErrInternalError, ""}
+ }
+ re1 := p.stack[n-1]
+ re2 := p.stack[n-2]
+ p.stack = p.stack[:n-2]
+ if re2.Op != opLeftParen {
+ return &Error{ErrMissingParen, p.wholeRegexp}
+ }
+ if re2.Cap == 0 {
+ // Just for grouping.
+ p.push(re1)
+ } else {
+ re2.Op = OpCapture
+ re2.Sub = re2.Sub0[:1]
+ re2.Sub[0] = re1
+ p.push(re2)
+ }
+ return nil
+}
+
+// parseEscape parses an escape sequence at the beginning of s
+// and returns the rune.
+func (p *parser) parseEscape(s string) (r int, rest string, err os.Error) {
+ t := s[1:]
+ if t == "" {
+ return 0, "", &Error{ErrTrailingBackslash, ""}
+ }
+ c, t, err := nextRune(t)
+ if err != nil {
+ return 0, "", err
+ }
+
+Switch:
+ switch c {
+ default:
+ if c < utf8.RuneSelf && !isalnum(c) {
+ // Escaped non-word characters are always themselves.
+ // PCRE is not quite so rigorous: it accepts things like
+ // \q, but we don't. We once rejected \_, but too many
+ // programs and people insist on using it, so allow \_.
+ return c, t, nil
+ }
+
+ // Octal escapes.
+ case '1', '2', '3', '4', '5', '6', '7':
+ // Single non-zero digit is a backreference; not supported
+ if t == "" || t[0] < '0' || t[0] > '7' {
+ break
+ }
+ fallthrough
+ case '0':
+ // Consume up to three octal digits; already have one.
+ r = c - '0'
+ for i := 1; i < 3; i++ {
+ if t == "" || t[0] < '0' || t[0] > '7' {
+ break
+ }
+ r = r*8 + int(t[0]) - '0'
+ t = t[1:]
+ }
+ return r, t, nil
+
+ // Hexadecimal escapes.
+ case 'x':
+ if t == "" {
+ break
+ }
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ if c == '{' {
+ // Any number of digits in braces.
+ // Perl accepts any text at all; it ignores all text
+ // after the first non-hex digit. We require only hex digits,
+ // and at least one.
+ nhex := 0
+ r = 0
+ for {
+ if t == "" {
+ break Switch
+ }
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ if c == '}' {
+ break
+ }
+ v := unhex(c)
+ if v < 0 {
+ break Switch
+ }
+ r = r*16 + v
+ if r > unicode.MaxRune {
+ break Switch
+ }
+ nhex++
+ }
+ if nhex == 0 {
+ break Switch
+ }
+ return r, t, nil
+ }
+
+ // Easy case: two hex digits.
+ x := unhex(c)
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ y := unhex(c)
+ if x < 0 || y < 0 {
+ break
+ }
+ return x*16 + y, t, nil
+
+ // C escapes. There is no case 'b', to avoid misparsing
+ // the Perl word-boundary \b as the C backspace \b
+ // when in POSIX mode. In Perl, /\b/ means word-boundary
+ // but /[\b]/ means backspace. We don't support that.
+ // If you want a backspace, embed a literal backspace
+ // character or use \x08.
+ case 'a':
+ return '\a', t, err
+ case 'f':
+ return '\f', t, err
+ case 'n':
+ return '\n', t, err
+ case 'r':
+ return '\r', t, err
+ case 't':
+ return '\t', t, err
+ case 'v':
+ return '\v', t, err
+ }
+ return 0, "", &Error{ErrInvalidEscape, s[:len(s)-len(t)]}
+}
+
+// parseClassChar parses a character class character at the beginning of s
+// and returns it.
+func (p *parser) parseClassChar(s, wholeClass string) (r int, rest string, err os.Error) {
+ if s == "" {
+ return 0, "", &Error{Code: ErrMissingBracket, Expr: wholeClass}
+ }
+
+ // Allow regular escape sequences even though
+ // many need not be escaped in this context.
+ if s[0] == '\\' {
+ return p.parseEscape(s)
+ }
+
+ return nextRune(s)
+}
+
+type charGroup struct {
+ sign int
+ class []int
+}
+
+// parsePerlClassEscape parses a leading Perl character class escape like \d
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parsePerlClassEscape(s string, r []int) (out []int, rest string) {
+ if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' {
+ return
+ }
+ g := perlGroup[s[0:2]]
+ if g.sign == 0 {
+ return
+ }
+ return p.appendGroup(r, g), s[2:]
+}
+
+// parseNamedClass parses a leading POSIX named character class like [:alnum:]
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parseNamedClass(s string, r []int) (out []int, rest string, err os.Error) {
+ if len(s) < 2 || s[0] != '[' || s[1] != ':' {
+ return
+ }
+
+ i := strings.Index(s[2:], ":]")
+ if i < 0 {
+ return
+ }
+ i += 2
+ name, s := s[0:i+2], s[i+2:]
+ g := posixGroup[name]
+ if g.sign == 0 {
+ return nil, "", &Error{ErrInvalidCharRange, name}
+ }
+ return p.appendGroup(r, g), s, nil
+}
+
+func (p *parser) appendGroup(r []int, g charGroup) []int {
+ if p.flags&FoldCase == 0 {
+ if g.sign < 0 {
+ r = appendNegatedClass(r, g.class)
+ } else {
+ r = appendClass(r, g.class)
+ }
+ } else {
+ tmp := p.tmpClass[:0]
+ tmp = appendFoldedClass(tmp, g.class)
+ p.tmpClass = tmp
+ tmp = cleanClass(&p.tmpClass)
+ if g.sign < 0 {
+ r = appendNegatedClass(r, tmp)
+ } else {
+ r = appendClass(r, tmp)
+ }
+ }
+ return r
+}
+
+// unicodeTable returns the unicode.RangeTable identified by name
+// and the table of additional fold-equivalent code points.
+func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) {
+ if t := unicode.Categories[name]; t != nil {
+ return t, unicode.FoldCategory[name]
+ }
+ if t := unicode.Scripts[name]; t != nil {
+ return t, unicode.FoldScript[name]
+ }
+ return nil, nil
+}
+
+// parseUnicodeClass parses a leading Unicode character class like \p{Han}
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parseUnicodeClass(s string, r []int) (out []int, rest string, err os.Error) {
+ if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' {
+ return
+ }
+
+ // Committed to parse or return error.
+ sign := +1
+ if s[1] == 'P' {
+ sign = -1
+ }
+ t := s[2:]
+ c, t, err := nextRune(t)
+ if err != nil {
+ return
+ }
+ var seq, name string
+ if c != '{' {
+ // Single-letter name.
+ seq = s[:len(s)-len(t)]
+ name = seq[2:]
+ } else {
+ // Name is in braces.
+ end := strings.IndexRune(s, '}')
+ if end < 0 {
+ if err = checkUTF8(s); err != nil {
+ return
+ }
+ return nil, "", &Error{ErrInvalidCharRange, s}
+ }
+ seq, t = s[:end+1], s[end+1:]
+ name = s[3:end]
+ if err = checkUTF8(name); err != nil {
+ return
+ }
+ }
+
+ // Group can have leading negation too. \p{^Han} == \P{Han}, \P{^Han} == \p{Han}.
+ if name != "" && name[0] == '^' {
+ sign = -sign
+ name = name[1:]
+ }
+
+ tab, fold := unicodeTable(name)
+ if tab == nil {
+ return nil, "", &Error{ErrInvalidCharRange, seq}
+ }
+
+ if p.flags&FoldCase == 0 || fold == nil {
+ if sign > 0 {
+ r = appendTable(r, tab)
+ } else {
+ r = appendNegatedTable(r, tab)
+ }
+ } else {
+ // Merge and clean tab and fold in a temporary buffer.
+ // This is necessary for the negative case and just tidy
+ // for the positive case.
+ tmp := p.tmpClass[:0]
+ tmp = appendTable(tmp, tab)
+ tmp = appendTable(tmp, fold)
+ p.tmpClass = tmp
+ tmp = cleanClass(&p.tmpClass)
+ if sign > 0 {
+ r = appendClass(r, tmp)
+ } else {
+ r = appendNegatedClass(r, tmp)
+ }
+ }
+ return r, t, nil
+}
+
+// parseClass parses a character class at the beginning of s
+// and pushes it onto the parse stack.
+func (p *parser) parseClass(s string) (rest string, err os.Error) {
+ t := s[1:] // chop [
+ re := p.newRegexp(OpCharClass)
+ re.Flags = p.flags
+ re.Rune = re.Rune0[:0]
+
+ sign := +1
+ if t != "" && t[0] == '^' {
+ sign = -1
+ t = t[1:]
+
+ // If character class does not match \n, add it here,
+ // so that negation later will do the right thing.
+ if p.flags&ClassNL == 0 {
+ re.Rune = append(re.Rune, '\n', '\n')
+ }
+ }
+
+ class := re.Rune
+ first := true // ] and - are okay as first char in class
+ for t == "" || t[0] != ']' || first {
+ // POSIX: - is only okay unescaped as first or last in class.
+ // Perl: - is okay anywhere.
+ if t != "" && t[0] == '-' && p.flags&PerlX == 0 && !first && (len(t) == 1 || t[1] != ']') {
+ _, size := utf8.DecodeRuneInString(t[1:])
+ return "", &Error{Code: ErrInvalidCharRange, Expr: t[:1+size]}
+ }
+ first = false
+
+ // Look for POSIX [:alnum:] etc.
+ if len(t) > 2 && t[0] == '[' && t[1] == ':' {
+ nclass, nt, err := p.parseNamedClass(t, class)
+ if err != nil {
+ return "", err
+ }
+ if nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+ }
+
+ // Look for Unicode character group like \p{Han}.
+ nclass, nt, err := p.parseUnicodeClass(t, class)
+ if err != nil {
+ return "", err
+ }
+ if nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+
+ // Look for Perl character class symbols (extension).
+ if nclass, nt := p.parsePerlClassEscape(t, class); nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+
+ // Single character or simple range.
+ rng := t
+ var lo, hi int
+ if lo, t, err = p.parseClassChar(t, s); err != nil {
+ return "", err
+ }
+ hi = lo
+ // [a-] means (a|-) so check for final ].
+ if len(t) >= 2 && t[0] == '-' && t[1] != ']' {
+ t = t[1:]
+ if hi, t, err = p.parseClassChar(t, s); err != nil {
+ return "", err
+ }
+ if hi < lo {
+ rng = rng[:len(rng)-len(t)]
+ return "", &Error{Code: ErrInvalidCharRange, Expr: rng}
+ }
+ }
+ if p.flags&FoldCase == 0 {
+ class = appendRange(class, lo, hi)
+ } else {
+ class = appendFoldedRange(class, lo, hi)
+ }
+ }
+ t = t[1:] // chop ]
+
+ // Use &re.Rune instead of &class to avoid allocation.
+ re.Rune = class
+ class = cleanClass(&re.Rune)
+ if sign < 0 {
+ class = negateClass(class)
+ }
+ re.Rune = class
+ p.push(re)
+ return t, nil
+}
+
+// cleanClass sorts the ranges (pairs of elements of r),
+// merges them, and eliminates duplicates.
+func cleanClass(rp *[]int) []int {
+
+ // Sort by lo increasing, hi decreasing to break ties.
+ sort.Sort(ranges{rp})
+
+ r := *rp
+ if len(r) < 2 {
+ return r
+ }
+
+ // Merge abutting, overlapping.
+ w := 2 // write index
+ for i := 2; i < len(r); i += 2 {
+ lo, hi := r[i], r[i+1]
+ if lo <= r[w-1]+1 {
+ // merge with previous range
+ if hi > r[w-1] {
+ r[w-1] = hi
+ }
+ continue
+ }
+ // new disjoint range
+ r[w] = lo
+ r[w+1] = hi
+ w += 2
+ }
+
+ return r[:w]
+}
+
+// appendRange returns the result of appending the range lo-hi to the class r.
+func appendRange(r []int, lo, hi int) []int {
+ // Expand last range or next to last range if it overlaps or abuts.
+ // Checking two ranges helps when appending case-folded
+ // alphabets, so that one range can be expanding A-Z and the
+ // other expanding a-z.
+ n := len(r)
+ for i := 2; i <= 4; i += 2 { // twice, using i=2, i=4
+ if n >= i {
+ rlo, rhi := r[n-i], r[n-i+1]
+ if lo <= rhi+1 && rlo <= hi+1 {
+ if lo < rlo {
+ r[n-i] = lo
+ }
+ if hi > rhi {
+ r[n-i+1] = hi
+ }
+ return r
+ }
+ }
+ }
+
+ return append(r, lo, hi)
+}
+
+const (
+ // minimum and maximum runes involved in folding.
+ // checked during test.
+ minFold = 0x0041
+ maxFold = 0x1044f
+)
+
+// appendFoldedRange returns the result of appending the range lo-hi
+// and its case folding-equivalent runes to the class r.
+func appendFoldedRange(r []int, lo, hi int) []int {
+ // Optimizations.
+ if lo <= minFold && hi >= maxFold {
+ // Range is full: folding can't add more.
+ return appendRange(r, lo, hi)
+ }
+ if hi < minFold || lo > maxFold {
+ // Range is outside folding possibilities.
+ return appendRange(r, lo, hi)
+ }
+ if lo < minFold {
+ // [lo, minFold-1] needs no folding.
+ r = appendRange(r, lo, minFold-1)
+ lo = minFold
+ }
+ if hi > maxFold {
+ // [maxFold+1, hi] needs no folding.
+ r = appendRange(r, maxFold+1, hi)
+ hi = maxFold
+ }
+
+ // Brute force. Depend on appendRange to coalesce ranges on the fly.
+ for c := lo; c <= hi; c++ {
+ r = appendRange(r, c, c)
+ f := unicode.SimpleFold(c)
+ for f != c {
+ r = appendRange(r, f, f)
+ f = unicode.SimpleFold(f)
+ }
+ }
+ return r
+}
+
+// appendClass returns the result of appending the class x to the class r.
+// It assume x is clean.
+func appendClass(r []int, x []int) []int {
+ for i := 0; i < len(x); i += 2 {
+ r = appendRange(r, x[i], x[i+1])
+ }
+ return r
+}
+
+// appendFolded returns the result of appending the case folding of the class x to the class r.
+func appendFoldedClass(r []int, x []int) []int {
+ for i := 0; i < len(x); i += 2 {
+ r = appendFoldedRange(r, x[i], x[i+1])
+ }
+ return r
+}
+
+// appendNegatedClass returns the result of appending the negation of the class x to the class r.
+// It assumes x is clean.
+func appendNegatedClass(r []int, x []int) []int {
+ nextLo := 0
+ for i := 0; i < len(x); i += 2 {
+ lo, hi := x[i], x[i+1]
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ }
+ if nextLo <= unicode.MaxRune {
+ r = appendRange(r, nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// appendTable returns the result of appending x to the class r.
+func appendTable(r []int, x *unicode.RangeTable) []int {
+ for _, xr := range x.R16 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ r = appendRange(r, lo, hi)
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ r = appendRange(r, c, c)
+ }
+ }
+ for _, xr := range x.R32 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ r = appendRange(r, lo, hi)
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ r = appendRange(r, c, c)
+ }
+ }
+ return r
+}
+
+// appendNegatedTable returns the result of appending the negation of x to the class r.
+func appendNegatedTable(r []int, x *unicode.RangeTable) []int {
+ nextLo := 0 // lo end of next class to add
+ for _, xr := range x.R16 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ if nextLo <= c-1 {
+ r = appendRange(r, nextLo, c-1)
+ }
+ nextLo = c + 1
+ }
+ }
+ for _, xr := range x.R32 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ if nextLo <= c-1 {
+ r = appendRange(r, nextLo, c-1)
+ }
+ nextLo = c + 1
+ }
+ }
+ if nextLo <= unicode.MaxRune {
+ r = appendRange(r, nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// negateClass overwrites r and returns r's negation.
+// It assumes the class r is already clean.
+func negateClass(r []int) []int {
+ nextLo := 0 // lo end of next class to add
+ w := 0 // write index
+ for i := 0; i < len(r); i += 2 {
+ lo, hi := r[i], r[i+1]
+ if nextLo <= lo-1 {
+ r[w] = nextLo
+ r[w+1] = lo - 1
+ w += 2
+ }
+ nextLo = hi + 1
+ }
+ r = r[:w]
+ if nextLo <= unicode.MaxRune {
+ // It's possible for the negation to have one more
+ // range - this one - than the original class, so use append.
+ r = append(r, nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// ranges implements sort.Interface on a []rune.
+// The choice of receiver type definition is strange
+// but avoids an allocation since we already have
+// a *[]int.
+type ranges struct {
+ p *[]int
+}
+
+func (ra ranges) Less(i, j int) bool {
+ p := *ra.p
+ i *= 2
+ j *= 2
+ return p[i] < p[j] || p[i] == p[j] && p[i+1] > p[j+1]
+}
+
+func (ra ranges) Len() int {
+ return len(*ra.p) / 2
+}
+
+func (ra ranges) Swap(i, j int) {
+ p := *ra.p
+ i *= 2
+ j *= 2
+ p[i], p[i+1], p[j], p[j+1] = p[j], p[j+1], p[i], p[i+1]
+}
+
+func checkUTF8(s string) os.Error {
+ for s != "" {
+ rune, size := utf8.DecodeRuneInString(s)
+ if rune == utf8.RuneError && size == 1 {
+ return &Error{Code: ErrInvalidUTF8, Expr: s}
+ }
+ s = s[size:]
+ }
+ return nil
+}
+
+func nextRune(s string) (c int, t string, err os.Error) {
+ c, size := utf8.DecodeRuneInString(s)
+ if c == utf8.RuneError && size == 1 {
+ return 0, "", &Error{Code: ErrInvalidUTF8, Expr: s}
+ }
+ return c, s[size:], nil
+}
+
+func isalnum(c int) bool {
+ return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+}
+
+func unhex(c int) int {
+ if '0' <= c && c <= '9' {
+ return c - '0'
+ }
+ if 'a' <= c && c <= 'f' {
+ return c - 'a' + 10
+ }
+ if 'A' <= c && c <= 'F' {
+ return c - 'A' + 10
+ }
+ return -1
+}
diff --git a/libgo/go/exp/regexp/syntax/parse_test.go b/libgo/go/exp/regexp/syntax/parse_test.go
new file mode 100644
index 00000000000..779b9afdeae
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/parse_test.go
@@ -0,0 +1,350 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+ "unicode"
+)
+
+var parseTests = []struct {
+ Regexp string
+ Dump string
+}{
+ // Base cases
+ {`a`, `lit{a}`},
+ {`a.`, `cat{lit{a}dot{}}`},
+ {`a.b`, `cat{lit{a}dot{}lit{b}}`},
+ {`ab`, `str{ab}`},
+ {`a.b.c`, `cat{lit{a}dot{}lit{b}dot{}lit{c}}`},
+ {`abc`, `str{abc}`},
+ {`a|^`, `alt{lit{a}bol{}}`},
+ {`a|b`, `cc{0x61-0x62}`},
+ {`(a)`, `cap{lit{a}}`},
+ {`(a)|b`, `alt{cap{lit{a}}lit{b}}`},
+ {`a*`, `star{lit{a}}`},
+ {`a+`, `plus{lit{a}}`},
+ {`a?`, `que{lit{a}}`},
+ {`a{2}`, `rep{2,2 lit{a}}`},
+ {`a{2,3}`, `rep{2,3 lit{a}}`},
+ {`a{2,}`, `rep{2,-1 lit{a}}`},
+ {`a*?`, `nstar{lit{a}}`},
+ {`a+?`, `nplus{lit{a}}`},
+ {`a??`, `nque{lit{a}}`},
+ {`a{2}?`, `nrep{2,2 lit{a}}`},
+ {`a{2,3}?`, `nrep{2,3 lit{a}}`},
+ {`a{2,}?`, `nrep{2,-1 lit{a}}`},
+ {``, `emp{}`},
+ {`|`, `emp{}`}, // alt{emp{}emp{}} but got factored
+ {`|x|`, `alt{emp{}lit{x}emp{}}`},
+ {`.`, `dot{}`},
+ {`^`, `bol{}`},
+ {`$`, `eol{}`},
+ {`\|`, `lit{|}`},
+ {`\(`, `lit{(}`},
+ {`\)`, `lit{)}`},
+ {`\*`, `lit{*}`},
+ {`\+`, `lit{+}`},
+ {`\?`, `lit{?}`},
+ {`{`, `lit{{}`},
+ {`}`, `lit{}}`},
+ {`\.`, `lit{.}`},
+ {`\^`, `lit{^}`},
+ {`\$`, `lit{$}`},
+ {`\\`, `lit{\}`},
+ {`[ace]`, `cc{0x61 0x63 0x65}`},
+ {`[abc]`, `cc{0x61-0x63}`},
+ {`[a-z]`, `cc{0x61-0x7a}`},
+ {`[a]`, `lit{a}`},
+ {`\-`, `lit{-}`},
+ {`-`, `lit{-}`},
+ {`\_`, `lit{_}`},
+ {`abc`, `str{abc}`},
+ {`abc|def`, `alt{str{abc}str{def}}`},
+ {`abc|def|ghi`, `alt{str{abc}str{def}str{ghi}}`},
+
+ // Posix and Perl extensions
+ {`[[:lower:]]`, `cc{0x61-0x7a}`},
+ {`[a-z]`, `cc{0x61-0x7a}`},
+ {`[^[:lower:]]`, `cc{0x0-0x60 0x7b-0x10ffff}`},
+ {`[[:^lower:]]`, `cc{0x0-0x60 0x7b-0x10ffff}`},
+ {`(?i)[[:lower:]]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`},
+ {`(?i)[a-z]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`},
+ {`(?i)[^[:lower:]]`, `cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+ {`(?i)[[:^lower:]]`, `cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+ {`\d`, `cc{0x30-0x39}`},
+ {`\D`, `cc{0x0-0x2f 0x3a-0x10ffff}`},
+ {`\s`, `cc{0x9-0xa 0xc-0xd 0x20}`},
+ {`\S`, `cc{0x0-0x8 0xb 0xe-0x1f 0x21-0x10ffff}`},
+ {`\w`, `cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a}`},
+ {`\W`, `cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x10ffff}`},
+ {`(?i)\w`, `cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a 0x17f 0x212a}`},
+ {`(?i)\W`, `cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`},
+ {`[^\\]`, `cc{0x0-0x5b 0x5d-0x10ffff}`},
+ // { `\C`, `byte{}` }, // probably never
+
+ // Unicode, negatives, and a double negative.
+ {`\p{Braille}`, `cc{0x2800-0x28ff}`},
+ {`\P{Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+ {`\p{^Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+ {`\P{^Braille}`, `cc{0x2800-0x28ff}`},
+ {`\pZ`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+ {`[\p{Braille}]`, `cc{0x2800-0x28ff}`},
+ {`[\P{Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+ {`[\p{^Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`},
+ {`[\P{^Braille}]`, `cc{0x2800-0x28ff}`},
+ {`[\pZ]`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`},
+ {`\p{Lu}`, mkCharClass(unicode.IsUpper)},
+ {`[\p{Lu}]`, mkCharClass(unicode.IsUpper)},
+ {`(?i)[\p{Lu}]`, mkCharClass(isUpperFold)},
+
+ // Hex, octal.
+ {`[\012-\234]\141`, `cat{cc{0xa-0x9c}lit{a}}`},
+ {`[\x{41}-\x7a]\x61`, `cat{cc{0x41-0x7a}lit{a}}`},
+
+ // More interesting regular expressions.
+ {`a{,2}`, `str{a{,2}}`},
+ {`\.\^\$\\`, `str{.^$\}`},
+ {`[a-zABC]`, `cc{0x41-0x43 0x61-0x7a}`},
+ {`[^a]`, `cc{0x0-0x60 0x62-0x10ffff}`},
+ {`[α-ε☺]`, `cc{0x3b1-0x3b5 0x263a}`}, // utf-8
+ {`a*{`, `cat{star{lit{a}}lit{{}}`},
+
+ // Test precedences
+ {`(?:ab)*`, `star{str{ab}}`},
+ {`(ab)*`, `star{cap{str{ab}}}`},
+ {`ab|cd`, `alt{str{ab}str{cd}}`},
+ {`a(b|c)d`, `cat{lit{a}cap{cc{0x62-0x63}}lit{d}}`},
+
+ // Test flattening.
+ {`(?:a)`, `lit{a}`},
+ {`(?:ab)(?:cd)`, `str{abcd}`},
+ {`(?:a+b+)(?:c+d+)`, `cat{plus{lit{a}}plus{lit{b}}plus{lit{c}}plus{lit{d}}}`},
+ {`(?:a+|b+)|(?:c+|d+)`, `alt{plus{lit{a}}plus{lit{b}}plus{lit{c}}plus{lit{d}}}`},
+ {`(?:a|b)|(?:c|d)`, `cc{0x61-0x64}`},
+ {`a|.`, `dot{}`},
+ {`.|a`, `dot{}`},
+ {`(?:[abc]|A|Z|hello|world)`, `alt{cc{0x41 0x5a 0x61-0x63}str{hello}str{world}}`},
+ {`(?:[abc]|A|Z)`, `cc{0x41 0x5a 0x61-0x63}`},
+
+ // Test Perl quoted literals
+ {`\Q+|*?{[\E`, `str{+|*?{[}`},
+ {`\Q+\E+`, `plus{lit{+}}`},
+ {`\Q\\E`, `lit{\}`},
+ {`\Q\\\E`, `str{\\}`},
+
+ // Test Perl \A and \z
+ {`(?m)^`, `bol{}`},
+ {`(?m)$`, `eol{}`},
+ {`(?-m)^`, `bot{}`},
+ {`(?-m)$`, `eot{}`},
+ {`(?m)\A`, `bot{}`},
+ {`(?m)\z`, `eot{\z}`},
+ {`(?-m)\A`, `bot{}`},
+ {`(?-m)\z`, `eot{\z}`},
+
+ // Test named captures
+ {`(?P<name>a)`, `cap{name:lit{a}}`},
+
+ // Case-folded literals
+ {`[Aa]`, `litfold{A}`},
+ {`[\x{100}\x{101}]`, `litfold{Ā}`},
+ {`[Δδ]`, `litfold{Δ}`},
+
+ // Strings
+ {`abcde`, `str{abcde}`},
+ {`[Aa][Bb]cd`, `cat{strfold{AB}str{cd}}`},
+
+ // Factoring.
+ {`abc|abd|aef|bcx|bcy`, `alt{cat{lit{a}alt{cat{lit{b}cc{0x63-0x64}}str{ef}}}cat{str{bc}cc{0x78-0x79}}}`},
+ {`ax+y|ax+z|ay+w`, `cat{lit{a}alt{cat{plus{lit{x}}cc{0x79-0x7a}}cat{plus{lit{y}}lit{w}}}}`},
+}
+
+const testFlags = MatchNL | PerlX | UnicodeGroups
+
+// Test Parse -> Dump.
+func TestParseDump(t *testing.T) {
+ for _, tt := range parseTests {
+ re, err := Parse(tt.Regexp, testFlags)
+ if err != nil {
+ t.Errorf("Parse(%#q): %v", tt.Regexp, err)
+ continue
+ }
+ d := dump(re)
+ if d != tt.Dump {
+ t.Errorf("Parse(%#q).Dump() = %#q want %#q", tt.Regexp, d, tt.Dump)
+ }
+ }
+}
+
+// dump prints a string representation of the regexp showing
+// the structure explicitly.
+func dump(re *Regexp) string {
+ var b bytes.Buffer
+ dumpRegexp(&b, re)
+ return b.String()
+}
+
+var opNames = []string{
+ OpNoMatch: "no",
+ OpEmptyMatch: "emp",
+ OpLiteral: "lit",
+ OpCharClass: "cc",
+ OpAnyCharNotNL: "dnl",
+ OpAnyChar: "dot",
+ OpBeginLine: "bol",
+ OpEndLine: "eol",
+ OpBeginText: "bot",
+ OpEndText: "eot",
+ OpWordBoundary: "wb",
+ OpNoWordBoundary: "nwb",
+ OpCapture: "cap",
+ OpStar: "star",
+ OpPlus: "plus",
+ OpQuest: "que",
+ OpRepeat: "rep",
+ OpConcat: "cat",
+ OpAlternate: "alt",
+}
+
+// dumpRegexp writes an encoding of the syntax tree for the regexp re to b.
+// It is used during testing to distinguish between parses that might print
+// the same using re's String method.
+func dumpRegexp(b *bytes.Buffer, re *Regexp) {
+ if int(re.Op) >= len(opNames) || opNames[re.Op] == "" {
+ fmt.Fprintf(b, "op%d", re.Op)
+ } else {
+ switch re.Op {
+ default:
+ b.WriteString(opNames[re.Op])
+ case OpStar, OpPlus, OpQuest, OpRepeat:
+ if re.Flags&NonGreedy != 0 {
+ b.WriteByte('n')
+ }
+ b.WriteString(opNames[re.Op])
+ case OpLiteral:
+ if len(re.Rune) > 1 {
+ b.WriteString("str")
+ } else {
+ b.WriteString("lit")
+ }
+ if re.Flags&FoldCase != 0 {
+ for _, r := range re.Rune {
+ if unicode.SimpleFold(r) != r {
+ b.WriteString("fold")
+ break
+ }
+ }
+ }
+ }
+ }
+ b.WriteByte('{')
+ switch re.Op {
+ case OpEndText:
+ if re.Flags&WasDollar == 0 {
+ b.WriteString(`\z`)
+ }
+ case OpLiteral:
+ for _, r := range re.Rune {
+ b.WriteRune(r)
+ }
+ case OpConcat, OpAlternate:
+ for _, sub := range re.Sub {
+ dumpRegexp(b, sub)
+ }
+ case OpStar, OpPlus, OpQuest:
+ dumpRegexp(b, re.Sub[0])
+ case OpRepeat:
+ fmt.Fprintf(b, "%d,%d ", re.Min, re.Max)
+ dumpRegexp(b, re.Sub[0])
+ case OpCapture:
+ if re.Name != "" {
+ b.WriteString(re.Name)
+ b.WriteByte(':')
+ }
+ dumpRegexp(b, re.Sub[0])
+ case OpCharClass:
+ sep := ""
+ for i := 0; i < len(re.Rune); i += 2 {
+ b.WriteString(sep)
+ sep = " "
+ lo, hi := re.Rune[i], re.Rune[i+1]
+ if lo == hi {
+ fmt.Fprintf(b, "%#x", lo)
+ } else {
+ fmt.Fprintf(b, "%#x-%#x", lo, hi)
+ }
+ }
+ }
+ b.WriteByte('}')
+}
+
+func mkCharClass(f func(int) bool) string {
+ re := &Regexp{Op: OpCharClass}
+ lo := -1
+ for i := 0; i <= unicode.MaxRune; i++ {
+ if f(i) {
+ if lo < 0 {
+ lo = i
+ }
+ } else {
+ if lo >= 0 {
+ re.Rune = append(re.Rune, lo, i-1)
+ lo = -1
+ }
+ }
+ }
+ if lo >= 0 {
+ re.Rune = append(re.Rune, lo, unicode.MaxRune)
+ }
+ return dump(re)
+}
+
+func isUpperFold(rune int) bool {
+ if unicode.IsUpper(rune) {
+ return true
+ }
+ c := unicode.SimpleFold(rune)
+ for c != rune {
+ if unicode.IsUpper(c) {
+ return true
+ }
+ c = unicode.SimpleFold(c)
+ }
+ return false
+}
+
+func TestFoldConstants(t *testing.T) {
+ last := -1
+ for i := 0; i <= unicode.MaxRune; i++ {
+ if unicode.SimpleFold(i) == i {
+ continue
+ }
+ if last == -1 && minFold != i {
+ t.Errorf("minFold=%#U should be %#U", minFold, i)
+ }
+ last = i
+ }
+ if maxFold != last {
+ t.Errorf("maxFold=%#U should be %#U", maxFold, last)
+ }
+}
+
+func TestAppendRangeCollapse(t *testing.T) {
+ // AppendRange should collapse each of the new ranges
+ // into the earlier ones (it looks back two ranges), so that
+ // the slice never grows very large.
+ // Note that we are not calling cleanClass.
+ var r []int
+ for i := 'A'; i <= 'Z'; i++ {
+ r = appendRange(r, i, i)
+ r = appendRange(r, i+'a'-'A', i+'a'-'A')
+ }
+ if string(r) != "AZaz" {
+ t.Errorf("appendRange interlaced A-Z a-z = %s, want AZaz", string(r))
+ }
+}
diff --git a/libgo/go/exp/regexp/syntax/perl_groups.go b/libgo/go/exp/regexp/syntax/perl_groups.go
new file mode 100644
index 00000000000..05b392c40d8
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/perl_groups.go
@@ -0,0 +1,130 @@
+// GENERATED BY make_perl_groups.pl; DO NOT EDIT.
+// make_perl_groups.pl >perl_groups.go
+
+package syntax
+
+var code1 = []int{ /* \d */
+ 0x30, 0x39,
+}
+
+var code2 = []int{ /* \s */
+ 0x9, 0xa,
+ 0xc, 0xd,
+ 0x20, 0x20,
+}
+
+var code3 = []int{ /* \w */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x5f, 0x5f,
+ 0x61, 0x7a,
+}
+
+var perlGroup = map[string]charGroup{
+ `\d`: {+1, code1},
+ `\D`: {-1, code1},
+ `\s`: {+1, code2},
+ `\S`: {-1, code2},
+ `\w`: {+1, code3},
+ `\W`: {-1, code3},
+}
+var code4 = []int{ /* [:alnum:] */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x61, 0x7a,
+}
+
+var code5 = []int{ /* [:alpha:] */
+ 0x41, 0x5a,
+ 0x61, 0x7a,
+}
+
+var code6 = []int{ /* [:ascii:] */
+ 0x0, 0x7f,
+}
+
+var code7 = []int{ /* [:blank:] */
+ 0x9, 0x9,
+ 0x20, 0x20,
+}
+
+var code8 = []int{ /* [:cntrl:] */
+ 0x0, 0x1f,
+ 0x7f, 0x7f,
+}
+
+var code9 = []int{ /* [:digit:] */
+ 0x30, 0x39,
+}
+
+var code10 = []int{ /* [:graph:] */
+ 0x21, 0x7e,
+}
+
+var code11 = []int{ /* [:lower:] */
+ 0x61, 0x7a,
+}
+
+var code12 = []int{ /* [:print:] */
+ 0x20, 0x7e,
+}
+
+var code13 = []int{ /* [:punct:] */
+ 0x21, 0x2f,
+ 0x3a, 0x40,
+ 0x5b, 0x60,
+ 0x7b, 0x7e,
+}
+
+var code14 = []int{ /* [:space:] */
+ 0x9, 0xd,
+ 0x20, 0x20,
+}
+
+var code15 = []int{ /* [:upper:] */
+ 0x41, 0x5a,
+}
+
+var code16 = []int{ /* [:word:] */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x5f, 0x5f,
+ 0x61, 0x7a,
+}
+
+var code17 = []int{ /* [:xdigit:] */
+ 0x30, 0x39,
+ 0x41, 0x46,
+ 0x61, 0x66,
+}
+
+var posixGroup = map[string]charGroup{
+ `[:alnum:]`: {+1, code4},
+ `[:^alnum:]`: {-1, code4},
+ `[:alpha:]`: {+1, code5},
+ `[:^alpha:]`: {-1, code5},
+ `[:ascii:]`: {+1, code6},
+ `[:^ascii:]`: {-1, code6},
+ `[:blank:]`: {+1, code7},
+ `[:^blank:]`: {-1, code7},
+ `[:cntrl:]`: {+1, code8},
+ `[:^cntrl:]`: {-1, code8},
+ `[:digit:]`: {+1, code9},
+ `[:^digit:]`: {-1, code9},
+ `[:graph:]`: {+1, code10},
+ `[:^graph:]`: {-1, code10},
+ `[:lower:]`: {+1, code11},
+ `[:^lower:]`: {-1, code11},
+ `[:print:]`: {+1, code12},
+ `[:^print:]`: {-1, code12},
+ `[:punct:]`: {+1, code13},
+ `[:^punct:]`: {-1, code13},
+ `[:space:]`: {+1, code14},
+ `[:^space:]`: {-1, code14},
+ `[:upper:]`: {+1, code15},
+ `[:^upper:]`: {-1, code15},
+ `[:word:]`: {+1, code16},
+ `[:^word:]`: {-1, code16},
+ `[:xdigit:]`: {+1, code17},
+ `[:^xdigit:]`: {-1, code17},
+}
diff --git a/libgo/go/exp/regexp/syntax/prog.go b/libgo/go/exp/regexp/syntax/prog.go
new file mode 100644
index 00000000000..bf85b720d02
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/prog.go
@@ -0,0 +1,237 @@
+package syntax
+
+import (
+ "bytes"
+ "strconv"
+)
+
+// Compiled program.
+// May not belong in this package, but convenient for now.
+
+// A Prog is a compiled regular expression program.
+type Prog struct {
+ Inst []Inst
+ Start int // index of start instruction
+ NumCap int // number of InstCapture insts in re
+}
+
+// An InstOp is an instruction opcode.
+type InstOp uint8
+
+const (
+ InstAlt InstOp = iota
+ InstAltMatch
+ InstCapture
+ InstEmptyWidth
+ InstMatch
+ InstFail
+ InstNop
+ InstRune
+)
+
+// An EmptyOp specifies a kind or mixture of zero-width assertions.
+type EmptyOp uint8
+
+const (
+ EmptyBeginLine EmptyOp = 1 << iota
+ EmptyEndLine
+ EmptyBeginText
+ EmptyEndText
+ EmptyWordBoundary
+ EmptyNoWordBoundary
+)
+
+// An Inst is a single instruction in a regular expression program.
+type Inst struct {
+ Op InstOp
+ Out uint32 // all but InstMatch, InstFail
+ Arg uint32 // InstAlt, InstAltMatch, InstCapture, InstEmptyWidth
+ Rune []int
+}
+
+func (p *Prog) String() string {
+ var b bytes.Buffer
+ dumpProg(&b, p)
+ return b.String()
+}
+
+// skipNop follows any no-op or capturing instructions
+// and returns the resulting pc.
+func (p *Prog) skipNop(pc uint32) *Inst {
+ i := &p.Inst[pc]
+ for i.Op == InstNop || i.Op == InstCapture {
+ pc = i.Out
+ i = &p.Inst[pc]
+ }
+ return i
+}
+
+// Prefix returns a literal string that all matches for the
+// regexp must start with. Complete is true if the prefix
+// is the entire match.
+func (p *Prog) Prefix() (prefix string, complete bool) {
+ i := p.skipNop(uint32(p.Start))
+
+ // Avoid allocation of buffer if prefix is empty.
+ if i.Op != InstRune || len(i.Rune) != 1 {
+ return "", i.Op == InstMatch
+ }
+
+ // Have prefix; gather characters.
+ var buf bytes.Buffer
+ for i.Op == InstRune && len(i.Rune) == 1 {
+ buf.WriteRune(i.Rune[0])
+ i = p.skipNop(i.Out)
+ }
+ return buf.String(), i.Op == InstMatch
+}
+
+// StartCond returns the leading empty-width conditions that must
+// be true in any match. It returns ^EmptyOp(0) if no matches are possible.
+func (p *Prog) StartCond() EmptyOp {
+ var flag EmptyOp
+ pc := uint32(p.Start)
+ i := &p.Inst[pc]
+Loop:
+ for {
+ switch i.Op {
+ case InstEmptyWidth:
+ flag |= EmptyOp(i.Arg)
+ case InstFail:
+ return ^EmptyOp(0)
+ case InstCapture, InstNop:
+ // skip
+ default:
+ break Loop
+ }
+ pc = i.Out
+ i = &p.Inst[pc]
+ }
+ return flag
+}
+
+// MatchRune returns true if the instruction matches (and consumes) r.
+// It should only be called when i.Op == InstRune.
+func (i *Inst) MatchRune(r int) bool {
+ rune := i.Rune
+
+ // Special case: single-rune slice is from literal string, not char class.
+ // TODO: Case folding.
+ if len(rune) == 1 {
+ return r == rune[0]
+ }
+
+ // Peek at the first few pairs.
+ // Should handle ASCII well.
+ for j := 0; j < len(rune) && j <= 8; j += 2 {
+ if r < rune[j] {
+ return false
+ }
+ if r <= rune[j+1] {
+ return true
+ }
+ }
+
+ // Otherwise binary search.
+ lo := 0
+ hi := len(rune) / 2
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ if c := rune[2*m]; c <= r {
+ if r <= rune[2*m+1] {
+ return true
+ }
+ lo = m + 1
+ } else {
+ hi = m
+ }
+ }
+ return false
+}
+
+// As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char.
+// Since we act on runes, it would be easy to support Unicode here.
+func wordRune(rune int) bool {
+ return rune == '_' ||
+ ('A' <= rune && rune <= 'Z') ||
+ ('a' <= rune && rune <= 'z') ||
+ ('0' <= rune && rune <= '9')
+}
+
+// MatchEmptyWidth returns true if the instruction matches
+// an empty string between the runes before and after.
+// It should only be called when i.Op == InstEmptyWidth.
+func (i *Inst) MatchEmptyWidth(before int, after int) bool {
+ switch EmptyOp(i.Arg) {
+ case EmptyBeginLine:
+ return before == '\n' || before == -1
+ case EmptyEndLine:
+ return after == '\n' || after == -1
+ case EmptyBeginText:
+ return before == -1
+ case EmptyEndText:
+ return after == -1
+ case EmptyWordBoundary:
+ return wordRune(before) != wordRune(after)
+ case EmptyNoWordBoundary:
+ return wordRune(before) == wordRune(after)
+ }
+ panic("unknown empty width arg")
+}
+
+func (i *Inst) String() string {
+ var b bytes.Buffer
+ dumpInst(&b, i)
+ return b.String()
+}
+
+func bw(b *bytes.Buffer, args ...string) {
+ for _, s := range args {
+ b.WriteString(s)
+ }
+}
+
+func dumpProg(b *bytes.Buffer, p *Prog) {
+ for j := range p.Inst {
+ i := &p.Inst[j]
+ pc := strconv.Itoa(j)
+ if len(pc) < 3 {
+ b.WriteString(" "[len(pc):])
+ }
+ if j == p.Start {
+ pc += "*"
+ }
+ bw(b, pc, "\t")
+ dumpInst(b, i)
+ bw(b, "\n")
+ }
+}
+
+func u32(i uint32) string {
+ return strconv.Uitoa64(uint64(i))
+}
+
+func dumpInst(b *bytes.Buffer, i *Inst) {
+ switch i.Op {
+ case InstAlt:
+ bw(b, "alt -> ", u32(i.Out), ", ", u32(i.Arg))
+ case InstAltMatch:
+ bw(b, "altmatch -> ", u32(i.Out), ", ", u32(i.Arg))
+ case InstCapture:
+ bw(b, "cap ", u32(i.Arg), " -> ", u32(i.Out))
+ case InstEmptyWidth:
+ bw(b, "empty ", u32(i.Arg), " -> ", u32(i.Out))
+ case InstMatch:
+ bw(b, "match")
+ case InstFail:
+ bw(b, "fail")
+ case InstNop:
+ bw(b, "nop -> ", u32(i.Out))
+ case InstRune:
+ if i.Rune == nil {
+ // shouldn't happen
+ bw(b, "rune <nil>")
+ }
+ bw(b, "rune ", strconv.QuoteToASCII(string(i.Rune)), " -> ", u32(i.Out))
+ }
+}
diff --git a/libgo/go/exp/regexp/syntax/prog_test.go b/libgo/go/exp/regexp/syntax/prog_test.go
new file mode 100644
index 00000000000..7be4281c27f
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/prog_test.go
@@ -0,0 +1,91 @@
+package syntax
+
+import (
+ "testing"
+)
+
+var compileTests = []struct {
+ Regexp string
+ Prog string
+}{
+ {"a", ` 0 fail
+ 1* rune "a" -> 2
+ 2 match
+`},
+ {"[A-M][n-z]", ` 0 fail
+ 1* rune "AM" -> 2
+ 2 rune "nz" -> 3
+ 3 match
+`},
+ {"", ` 0 fail
+ 1* nop -> 2
+ 2 match
+`},
+ {"a?", ` 0 fail
+ 1 rune "a" -> 3
+ 2* alt -> 1, 3
+ 3 match
+`},
+ {"a??", ` 0 fail
+ 1 rune "a" -> 3
+ 2* alt -> 3, 1
+ 3 match
+`},
+ {"a+", ` 0 fail
+ 1* rune "a" -> 2
+ 2 alt -> 1, 3
+ 3 match
+`},
+ {"a+?", ` 0 fail
+ 1* rune "a" -> 2
+ 2 alt -> 3, 1
+ 3 match
+`},
+ {"a*", ` 0 fail
+ 1 rune "a" -> 2
+ 2* alt -> 1, 3
+ 3 match
+`},
+ {"a*?", ` 0 fail
+ 1 rune "a" -> 2
+ 2* alt -> 3, 1
+ 3 match
+`},
+ {"a+b+", ` 0 fail
+ 1* rune "a" -> 2
+ 2 alt -> 1, 3
+ 3 rune "b" -> 4
+ 4 alt -> 3, 5
+ 5 match
+`},
+ {"(a+)(b+)", ` 0 fail
+ 1* cap 2 -> 2
+ 2 rune "a" -> 3
+ 3 alt -> 2, 4
+ 4 cap 3 -> 5
+ 5 cap 4 -> 6
+ 6 rune "b" -> 7
+ 7 alt -> 6, 8
+ 8 cap 5 -> 9
+ 9 match
+`},
+ {"a+|b+", ` 0 fail
+ 1 rune "a" -> 2
+ 2 alt -> 1, 6
+ 3 rune "b" -> 4
+ 4 alt -> 3, 6
+ 5* alt -> 1, 3
+ 6 match
+`},
+}
+
+func TestCompile(t *testing.T) {
+ for _, tt := range compileTests {
+ re, _ := Parse(tt.Regexp, Perl)
+ p, _ := Compile(re)
+ s := p.String()
+ if s != tt.Prog {
+ t.Errorf("compiled %#q:\n--- have\n%s---\n--- want\n%s---", tt.Regexp, s, tt.Prog)
+ }
+ }
+}
diff --git a/libgo/go/exp/regexp/syntax/regexp.go b/libgo/go/exp/regexp/syntax/regexp.go
new file mode 100644
index 00000000000..00a4addefc4
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/regexp.go
@@ -0,0 +1,284 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package syntax parses regular expressions into syntax trees.
+// WORK IN PROGRESS.
+package syntax
+
+// Note to implementers:
+// In this package, re is always a *Regexp and r is always a rune.
+
+import (
+ "bytes"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+// A Regexp is a node in a regular expression syntax tree.
+type Regexp struct {
+ Op Op // operator
+ Flags Flags
+ Sub []*Regexp // subexpressions, if any
+ Sub0 [1]*Regexp // storage for short Sub
+ Rune []int // matched runes, for OpLiteral, OpCharClass
+ Rune0 [2]int // storage for short Rune
+ Min, Max int // min, max for OpRepeat
+ Cap int // capturing index, for OpCapture
+ Name string // capturing name, for OpCapture
+}
+
+// An Op is a single regular expression operator.
+type Op uint8
+
+// Operators are listed in precedence order, tightest binding to weakest.
+// Character class operators are listed simplest to most complex
+// (OpLiteral, OpCharClass, OpAnyCharNotNL, OpAnyChar).
+
+const (
+ OpNoMatch Op = 1 + iota // matches no strings
+ OpEmptyMatch // matches empty string
+ OpLiteral // matches Runes sequence
+ OpCharClass // matches Runes interpreted as range pair list
+ OpAnyCharNotNL // matches any character
+ OpAnyChar // matches any character
+ OpBeginLine // matches empty string at beginning of line
+ OpEndLine // matches empty string at end of line
+ OpBeginText // matches empty string at beginning of text
+ OpEndText // matches empty string at end of text
+ OpWordBoundary // matches word boundary `\b`
+ OpNoWordBoundary // matches word non-boundary `\B`
+ OpCapture // capturing subexpression with index Cap, optional name Name
+ OpStar // matches Sub[0] zero or more times
+ OpPlus // matches Sub[0] one or more times
+ OpQuest // matches Sub[0] zero or one times
+ OpRepeat // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit)
+ OpConcat // matches concatenation of Subs
+ OpAlternate // matches alternation of Subs
+)
+
+const opPseudo Op = 128 // where pseudo-ops start
+
+// Equal returns true if x and y have identical structure.
+func (x *Regexp) Equal(y *Regexp) bool {
+ if x == nil || y == nil {
+ return x == y
+ }
+ if x.Op != y.Op {
+ return false
+ }
+ switch x.Op {
+ case OpEndText:
+ // The parse flags remember whether this is \z or \Z.
+ if x.Flags&WasDollar != y.Flags&WasDollar {
+ return false
+ }
+
+ case OpLiteral, OpCharClass:
+ if len(x.Rune) != len(y.Rune) {
+ return false
+ }
+ for i, r := range x.Rune {
+ if r != y.Rune[i] {
+ return false
+ }
+ }
+
+ case OpAlternate, OpConcat:
+ if len(x.Sub) != len(y.Sub) {
+ return false
+ }
+ for i, sub := range x.Sub {
+ if !sub.Equal(y.Sub[i]) {
+ return false
+ }
+ }
+
+ case OpStar, OpPlus, OpQuest:
+ if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) {
+ return false
+ }
+
+ case OpRepeat:
+ if x.Flags&NonGreedy != y.Flags&NonGreedy || x.Min != y.Min || x.Max != y.Max || !x.Sub[0].Equal(y.Sub[0]) {
+ return false
+ }
+
+ case OpCapture:
+ if x.Cap != y.Cap || x.Name != y.Name || !x.Sub[0].Equal(y.Sub[0]) {
+ return false
+ }
+ }
+ return true
+}
+
+// writeRegexp writes the Perl syntax for the regular expression re to b.
+func writeRegexp(b *bytes.Buffer, re *Regexp) {
+ switch re.Op {
+ default:
+ b.WriteString("<invalid op" + strconv.Itoa(int(re.Op)) + ">")
+ case OpNoMatch:
+ b.WriteString(`[^\x00-\x{10FFFF}]`)
+ case OpEmptyMatch:
+ b.WriteString(`(?:)`)
+ case OpLiteral:
+ if re.Flags&FoldCase != 0 {
+ b.WriteString(`(?i:`)
+ }
+ for _, r := range re.Rune {
+ escape(b, r, false)
+ }
+ if re.Flags&FoldCase != 0 {
+ b.WriteString(`)`)
+ }
+ case OpCharClass:
+ if len(re.Rune)%2 != 0 {
+ b.WriteString(`[invalid char class]`)
+ break
+ }
+ b.WriteRune('[')
+ if len(re.Rune) == 0 {
+ b.WriteString(`^\x00-\x{10FFFF}`)
+ } else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
+ // Contains 0 and MaxRune. Probably a negated class.
+ // Print the gaps.
+ b.WriteRune('^')
+ for i := 1; i < len(re.Rune)-1; i += 2 {
+ lo, hi := re.Rune[i]+1, re.Rune[i+1]-1
+ escape(b, lo, lo == '-')
+ if lo != hi {
+ b.WriteRune('-')
+ escape(b, hi, hi == '-')
+ }
+ }
+ } else {
+ for i := 0; i < len(re.Rune); i += 2 {
+ lo, hi := re.Rune[i], re.Rune[i+1]
+ escape(b, lo, lo == '-')
+ if lo != hi {
+ b.WriteRune('-')
+ escape(b, hi, hi == '-')
+ }
+ }
+ }
+ b.WriteRune(']')
+ case OpAnyCharNotNL:
+ b.WriteString(`[^\n]`)
+ case OpAnyChar:
+ b.WriteRune('.')
+ case OpBeginLine:
+ b.WriteRune('^')
+ case OpEndLine:
+ b.WriteRune('$')
+ case OpBeginText:
+ b.WriteString(`\A`)
+ case OpEndText:
+ b.WriteString(`\z`)
+ case OpWordBoundary:
+ b.WriteString(`\b`)
+ case OpNoWordBoundary:
+ b.WriteString(`\B`)
+ case OpCapture:
+ if re.Name != "" {
+ b.WriteString(`(?P<`)
+ b.WriteString(re.Name)
+ b.WriteRune('>')
+ } else {
+ b.WriteRune('(')
+ }
+ if re.Sub[0].Op != OpEmptyMatch {
+ writeRegexp(b, re.Sub[0])
+ }
+ b.WriteRune(')')
+ case OpStar, OpPlus, OpQuest, OpRepeat:
+ if sub := re.Sub[0]; sub.Op > OpCapture {
+ b.WriteString(`(?:`)
+ writeRegexp(b, sub)
+ b.WriteString(`)`)
+ } else {
+ writeRegexp(b, sub)
+ }
+ switch re.Op {
+ case OpStar:
+ b.WriteRune('*')
+ case OpPlus:
+ b.WriteRune('+')
+ case OpQuest:
+ b.WriteRune('?')
+ case OpRepeat:
+ b.WriteRune('{')
+ b.WriteString(strconv.Itoa(re.Min))
+ if re.Max != re.Min {
+ b.WriteRune(',')
+ if re.Max >= 0 {
+ b.WriteString(strconv.Itoa(re.Max))
+ }
+ }
+ b.WriteRune('}')
+ }
+ case OpConcat:
+ for _, sub := range re.Sub {
+ if sub.Op == OpAlternate {
+ b.WriteString(`(?:`)
+ writeRegexp(b, sub)
+ b.WriteString(`)`)
+ } else {
+ writeRegexp(b, sub)
+ }
+ }
+ case OpAlternate:
+ for i, sub := range re.Sub {
+ if i > 0 {
+ b.WriteRune('|')
+ }
+ writeRegexp(b, sub)
+ }
+ }
+}
+
+func (re *Regexp) String() string {
+ var b bytes.Buffer
+ writeRegexp(&b, re)
+ return b.String()
+}
+
+const meta = `\.+*?()|[]{}^$`
+
+func escape(b *bytes.Buffer, r int, force bool) {
+ if unicode.IsPrint(r) {
+ if strings.IndexRune(meta, r) >= 0 || force {
+ b.WriteRune('\\')
+ }
+ b.WriteRune(r)
+ return
+ }
+
+ switch r {
+ case '\a':
+ b.WriteString(`\a`)
+ case '\f':
+ b.WriteString(`\f`)
+ case '\n':
+ b.WriteString(`\n`)
+ case '\r':
+ b.WriteString(`\r`)
+ case '\t':
+ b.WriteString(`\t`)
+ case '\v':
+ b.WriteString(`\v`)
+ default:
+ if r < 0x100 {
+ b.WriteString(`\x`)
+ s := strconv.Itob(r, 16)
+ if len(s) == 1 {
+ b.WriteRune('0')
+ }
+ b.WriteString(s)
+ break
+ }
+ b.WriteString(`\x{`)
+ b.WriteString(strconv.Itob(r, 16))
+ b.WriteString(`}`)
+ }
+}
diff --git a/libgo/go/exp/regexp/syntax/simplify.go b/libgo/go/exp/regexp/syntax/simplify.go
new file mode 100644
index 00000000000..72390417bbe
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/simplify.go
@@ -0,0 +1,151 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+// Simplify returns a regexp equivalent to re but without counted repetitions
+// and with various other simplifications, such as rewriting /(?:a+)+/ to /a+/.
+// The resulting regexp will execute correctly but its string representation
+// will not produce the same parse tree, because capturing parentheses
+// may have been duplicated or removed. For example, the simplified form
+// for /(x){1,2}/ is /(x)(x)?/ but both parentheses capture as $1.
+// The returned regexp may share structure with or be the original.
+func (re *Regexp) Simplify() *Regexp {
+ if re == nil {
+ return nil
+ }
+ switch re.Op {
+ case OpCapture, OpConcat, OpAlternate:
+ // Simplify children, building new Regexp if children change.
+ nre := re
+ for i, sub := range re.Sub {
+ nsub := sub.Simplify()
+ if nre == re && nsub != sub {
+ // Start a copy.
+ nre = new(Regexp)
+ *nre = *re
+ nre.Rune = nil
+ nre.Sub = append(nre.Sub0[:0], re.Sub[:i]...)
+ }
+ if nre != re {
+ nre.Sub = append(nre.Sub, nsub)
+ }
+ }
+ return nre
+
+ case OpStar, OpPlus, OpQuest:
+ sub := re.Sub[0].Simplify()
+ return simplify1(re.Op, re.Flags, sub, re)
+
+ case OpRepeat:
+ // Special special case: x{0} matches the empty string
+ // and doesn't even need to consider x.
+ if re.Min == 0 && re.Max == 0 {
+ return &Regexp{Op: OpEmptyMatch}
+ }
+
+ // The fun begins.
+ sub := re.Sub[0].Simplify()
+
+ // x{n,} means at least n matches of x.
+ if re.Max == -1 {
+ // Special case: x{0,} is x*.
+ if re.Min == 0 {
+ return simplify1(OpStar, re.Flags, sub, nil)
+ }
+
+ // Special case: x{1,} is x+.
+ if re.Min == 1 {
+ return simplify1(OpPlus, re.Flags, sub, nil)
+ }
+
+ // General case: x{4,} is xxxx+.
+ nre := &Regexp{Op: OpConcat}
+ nre.Sub = nre.Sub0[:0]
+ for i := 0; i < re.Min-1; i++ {
+ nre.Sub = append(nre.Sub, sub)
+ }
+ nre.Sub = append(nre.Sub, simplify1(OpPlus, re.Flags, sub, nil))
+ return nre
+ }
+
+ // Special case x{0} handled above.
+
+ // Special case: x{1} is just x.
+ if re.Min == 1 && re.Max == 1 {
+ return sub
+ }
+
+ // General case: x{n,m} means n copies of x and m copies of x?
+ // The machine will do less work if we nest the final m copies,
+ // so that x{2,5} = xx(x(x(x)?)?)?
+
+ // Build leading prefix: xx.
+ var prefix *Regexp
+ if re.Min > 0 {
+ prefix = &Regexp{Op: OpConcat}
+ prefix.Sub = prefix.Sub0[:0]
+ for i := 0; i < re.Min; i++ {
+ prefix.Sub = append(prefix.Sub, sub)
+ }
+ }
+
+ // Build and attach suffix: (x(x(x)?)?)?
+ if re.Max > re.Min {
+ suffix := simplify1(OpQuest, re.Flags, sub, nil)
+ for i := re.Min + 1; i < re.Max; i++ {
+ nre2 := &Regexp{Op: OpConcat}
+ nre2.Sub = append(nre2.Sub0[:0], sub, suffix)
+ suffix = simplify1(OpQuest, re.Flags, nre2, nil)
+ }
+ if prefix == nil {
+ return suffix
+ }
+ prefix.Sub = append(prefix.Sub, suffix)
+ }
+ if prefix != nil {
+ return prefix
+ }
+
+ // Some degenerate case like min > max or min < max < 0.
+ // Handle as impossible match.
+ return &Regexp{Op: OpNoMatch}
+ }
+
+ return re
+}
+
+// simplify1 implements Simplify for the unary OpStar,
+// OpPlus, and OpQuest operators. It returns the simple regexp
+// equivalent to
+//
+// Regexp{Op: op, Flags: flags, Sub: {sub}}
+//
+// under the assumption that sub is already simple, and
+// without first allocating that structure. If the regexp
+// to be returned turns out to be equivalent to re, simplify1
+// returns re instead.
+//
+// simplify1 is factored out of Simplify because the implementation
+// for other operators generates these unary expressions.
+// Letting them call simplify1 makes sure the expressions they
+// generate are simple.
+func simplify1(op Op, flags Flags, sub, re *Regexp) *Regexp {
+ // Special case: repeat the empty string as much as
+ // you want, but it's still the empty string.
+ if sub.Op == OpEmptyMatch {
+ return sub
+ }
+ // The operators are idempotent if the flags match.
+ if op == sub.Op && flags&NonGreedy == sub.Flags&NonGreedy {
+ return sub
+ }
+ if re != nil && re.Op == op && re.Flags&NonGreedy == flags&NonGreedy && sub == re.Sub[0] {
+ return re
+ }
+
+ re = &Regexp{Op: op, Flags: flags}
+ re.Sub = append(re.Sub0[:0], sub)
+ return re
+}
diff --git a/libgo/go/exp/regexp/syntax/simplify_test.go b/libgo/go/exp/regexp/syntax/simplify_test.go
new file mode 100644
index 00000000000..c8cec21831a
--- /dev/null
+++ b/libgo/go/exp/regexp/syntax/simplify_test.go
@@ -0,0 +1,151 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import "testing"
+
+var simplifyTests = []struct {
+ Regexp string
+ Simple string
+}{
+ // Already-simple constructs
+ {`a`, `a`},
+ {`ab`, `ab`},
+ {`a|b`, `[a-b]`},
+ {`ab|cd`, `ab|cd`},
+ {`(ab)*`, `(ab)*`},
+ {`(ab)+`, `(ab)+`},
+ {`(ab)?`, `(ab)?`},
+ {`.`, `.`},
+ {`^`, `^`},
+ {`$`, `$`},
+ {`[ac]`, `[ac]`},
+ {`[^ac]`, `[^ac]`},
+
+ // Posix character classes
+ {`[[:alnum:]]`, `[0-9A-Za-z]`},
+ {`[[:alpha:]]`, `[A-Za-z]`},
+ {`[[:blank:]]`, `[\t ]`},
+ {`[[:cntrl:]]`, `[\x00-\x1f\x7f]`},
+ {`[[:digit:]]`, `[0-9]`},
+ {`[[:graph:]]`, `[!-~]`},
+ {`[[:lower:]]`, `[a-z]`},
+ {`[[:print:]]`, `[ -~]`},
+ {`[[:punct:]]`, "[!-/:-@\\[-`\\{-~]"},
+ {`[[:space:]]`, `[\t-\r ]`},
+ {`[[:upper:]]`, `[A-Z]`},
+ {`[[:xdigit:]]`, `[0-9A-Fa-f]`},
+
+ // Perl character classes
+ {`\d`, `[0-9]`},
+ {`\s`, `[\t-\n\f-\r ]`},
+ {`\w`, `[0-9A-Z_a-z]`},
+ {`\D`, `[^0-9]`},
+ {`\S`, `[^\t-\n\f-\r ]`},
+ {`\W`, `[^0-9A-Z_a-z]`},
+ {`[\d]`, `[0-9]`},
+ {`[\s]`, `[\t-\n\f-\r ]`},
+ {`[\w]`, `[0-9A-Z_a-z]`},
+ {`[\D]`, `[^0-9]`},
+ {`[\S]`, `[^\t-\n\f-\r ]`},
+ {`[\W]`, `[^0-9A-Z_a-z]`},
+
+ // Posix repetitions
+ {`a{1}`, `a`},
+ {`a{2}`, `aa`},
+ {`a{5}`, `aaaaa`},
+ {`a{0,1}`, `a?`},
+ // The next three are illegible because Simplify inserts (?:)
+ // parens instead of () parens to avoid creating extra
+ // captured subexpressions. The comments show a version with fewer parens.
+ {`(a){0,2}`, `(?:(a)(a)?)?`}, // (aa?)?
+ {`(a){0,4}`, `(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // (a(a(aa?)?)?)?
+ {`(a){2,6}`, `(a)(a)(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // aa(a(a(aa?)?)?)?
+ {`a{0,2}`, `(?:aa?)?`}, // (aa?)?
+ {`a{0,4}`, `(?:a(?:a(?:aa?)?)?)?`}, // (a(a(aa?)?)?)?
+ {`a{2,6}`, `aa(?:a(?:a(?:aa?)?)?)?`}, // aa(a(a(aa?)?)?)?
+ {`a{0,}`, `a*`},
+ {`a{1,}`, `a+`},
+ {`a{2,}`, `aa+`},
+ {`a{5,}`, `aaaaa+`},
+
+ // Test that operators simplify their arguments.
+ {`(?:a{1,}){1,}`, `a+`},
+ {`(a{1,}b{1,})`, `(a+b+)`},
+ {`a{1,}|b{1,}`, `a+|b+`},
+ {`(?:a{1,})*`, `(?:a+)*`},
+ {`(?:a{1,})+`, `a+`},
+ {`(?:a{1,})?`, `(?:a+)?`},
+ {``, `(?:)`},
+ {`a{0}`, `(?:)`},
+
+ // Character class simplification
+ {`[ab]`, `[a-b]`},
+ {`[a-za-za-z]`, `[a-z]`},
+ {`[A-Za-zA-Za-z]`, `[A-Za-z]`},
+ {`[ABCDEFGH]`, `[A-H]`},
+ {`[AB-CD-EF-GH]`, `[A-H]`},
+ {`[W-ZP-XE-R]`, `[E-Z]`},
+ {`[a-ee-gg-m]`, `[a-m]`},
+ {`[a-ea-ha-m]`, `[a-m]`},
+ {`[a-ma-ha-e]`, `[a-m]`},
+ {`[a-zA-Z0-9 -~]`, `[ -~]`},
+
+ // Empty character classes
+ {`[^[:cntrl:][:^cntrl:]]`, `[^\x00-\x{10FFFF}]`},
+
+ // Full character classes
+ {`[[:cntrl:][:^cntrl:]]`, `.`},
+
+ // Unicode case folding.
+ {`(?i)A`, `(?i:A)`},
+ {`(?i)a`, `(?i:a)`},
+ {`(?i)[A]`, `(?i:A)`},
+ {`(?i)[a]`, `(?i:A)`},
+ {`(?i)K`, `(?i:K)`},
+ {`(?i)k`, `(?i:k)`},
+ {`(?i)\x{212a}`, "(?i:\u212A)"},
+ {`(?i)[K]`, "[Kk\u212A]"},
+ {`(?i)[k]`, "[Kk\u212A]"},
+ {`(?i)[\x{212a}]`, "[Kk\u212A]"},
+ {`(?i)[a-z]`, "[A-Za-z\u017F\u212A]"},
+ {`(?i)[\x00-\x{FFFD}]`, "[\\x00-\uFFFD]"},
+ {`(?i)[\x00-\x{10FFFF}]`, `.`},
+
+ // Empty string as a regular expression.
+ // The empty string must be preserved inside parens in order
+ // to make submatches work right, so these tests are less
+ // interesting than they might otherwise be. String inserts
+ // explicit (?:) in place of non-parenthesized empty strings,
+ // to make them easier to spot for other parsers.
+ {`(a|b|)`, `([a-b]|(?:))`},
+ {`(|)`, `()`},
+ {`a()`, `a()`},
+ {`(()|())`, `(()|())`},
+ {`(a|)`, `(a|(?:))`},
+ {`ab()cd()`, `ab()cd()`},
+ {`()`, `()`},
+ {`()*`, `()*`},
+ {`()+`, `()+`},
+ {`()?`, `()?`},
+ {`(){0}`, `(?:)`},
+ {`(){1}`, `()`},
+ {`(){1,}`, `()+`},
+ {`(){0,2}`, `(?:()()?)?`},
+}
+
+func TestSimplify(t *testing.T) {
+ for _, tt := range simplifyTests {
+ re, err := Parse(tt.Regexp, MatchNL|Perl&^OneLine)
+ if err != nil {
+ t.Errorf("Parse(%#q) = error %v", tt.Regexp, err)
+ continue
+ }
+ s := re.Simplify().String()
+ if s != tt.Simple {
+ t.Errorf("Simplify(%#q) = %#q, want %#q", tt.Regexp, s, tt.Simple)
+ }
+ }
+}
diff --git a/libgo/go/exp/template/html/context.go b/libgo/go/exp/template/html/context.go
new file mode 100644
index 00000000000..41100688343
--- /dev/null
+++ b/libgo/go/exp/template/html/context.go
@@ -0,0 +1,98 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "fmt"
+)
+
+// context describes the state an HTML parser must be in when it reaches the
+// portion of HTML produced by evaluating a particular template node.
+//
+// The zero value of type context is the start context for a template that
+// produces an HTML fragment as defined at
+// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments
+// where the context element is null.
+type context struct {
+ state state
+ delim delim
+}
+
+func (c context) String() string {
+ return fmt.Sprintf("context{state: %s, delim: %s", c.state, c.delim)
+}
+
+// eq is true if the two contexts are identical field-wise.
+func (c context) eq(d context) bool {
+ return c.state == d.state && c.delim == d.delim
+}
+
+// state describes a high-level HTML parser state.
+//
+// It bounds the top of the element stack, and by extension the HTML
+// insertion mode, but also contains state that does not correspond to
+// anything in the HTML5 parsing algorithm because a single token
+// production in the HTML grammar may contain embedded actions in a template.
+// For instance, the quoted HTML attribute produced by
+// <div title="Hello {{.World}}">
+// is a single token in HTML's grammar but in a template spans several nodes.
+type state uint8
+
+const (
+ // statePCDATA is parsed character data. An HTML parser is in
+ // this state when its parse position is outside an HTML tag,
+ // directive, comment, and special element body.
+ statePCDATA state = iota
+ // stateTag occurs before an HTML attribute or the end of a tag.
+ stateTag
+ // stateURI occurs inside an HTML attribute whose content is a URI.
+ stateURI
+ // stateError is an infectious error state outside any valid
+ // HTML/CSS/JS construct.
+ stateError
+)
+
+var stateNames = [...]string{
+ statePCDATA: "statePCDATA",
+ stateTag: "stateTag",
+ stateURI: "stateURI",
+ stateError: "stateError",
+}
+
+func (s state) String() string {
+ if uint(s) < uint(len(stateNames)) {
+ return stateNames[s]
+ }
+ return fmt.Sprintf("illegal state %d", uint(s))
+}
+
+// delim is the delimiter that will end the current HTML attribute.
+type delim uint8
+
+const (
+ // delimNone occurs outside any attribute.
+ delimNone delim = iota
+ // delimDoubleQuote occurs when a double quote (") closes the attribute.
+ delimDoubleQuote
+ // delimSingleQuote occurs when a single quote (') closes the attribute.
+ delimSingleQuote
+ // delimSpaceOrTagEnd occurs when a space or right angle bracket (>)
+ // closes the attribute.
+ delimSpaceOrTagEnd
+)
+
+var delimNames = [...]string{
+ delimNone: "delimNone",
+ delimDoubleQuote: "delimDoubleQuote",
+ delimSingleQuote: "delimSingleQuote",
+ delimSpaceOrTagEnd: "delimSpaceOrTagEnd",
+}
+
+func (d delim) String() string {
+ if uint(d) < uint(len(delimNames)) {
+ return delimNames[d]
+ }
+ return fmt.Sprintf("illegal delim %d", uint(d))
+}
diff --git a/libgo/go/exp/template/html/escape.go b/libgo/go/exp/template/html/escape.go
new file mode 100644
index 00000000000..e0e87b98d04
--- /dev/null
+++ b/libgo/go/exp/template/html/escape.go
@@ -0,0 +1,105 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package html is a specialization of exp/template that automates the
+// construction of safe HTML output.
+// At the moment, the escaping is naive. All dynamic content is assumed to be
+// plain text interpolated in an HTML PCDATA context.
+package html
+
+import (
+ "template"
+ "template/parse"
+)
+
+// Escape rewrites each action in the template to guarantee the output is
+// HTML-escaped.
+func Escape(t *template.Template) {
+ // If the parser shares trees based on common-subexpression
+ // joining then we will need to avoid multiply escaping the same action.
+ escapeListNode(t.Tree.Root)
+}
+
+// escapeNode dispatches to escape<NodeType> helpers by type.
+func escapeNode(node parse.Node) {
+ switch n := node.(type) {
+ case *parse.ListNode:
+ escapeListNode(n)
+ case *parse.TextNode:
+ // Nothing to do.
+ case *parse.ActionNode:
+ escapeActionNode(n)
+ case *parse.IfNode:
+ escapeIfNode(n)
+ case *parse.RangeNode:
+ escapeRangeNode(n)
+ case *parse.TemplateNode:
+ // Nothing to do.
+ case *parse.WithNode:
+ escapeWithNode(n)
+ default:
+ panic("handling for " + node.String() + " not implemented")
+ // TODO: Handle other inner node types.
+ }
+}
+
+// escapeListNode recursively escapes its input's children.
+func escapeListNode(node *parse.ListNode) {
+ if node == nil {
+ return
+ }
+ children := node.Nodes
+ for _, child := range children {
+ escapeNode(child)
+ }
+}
+
+// escapeActionNode adds a pipeline call to the end that escapes the result
+// of the expression before it is interpolated into the template output.
+func escapeActionNode(node *parse.ActionNode) {
+ pipe := node.Pipe
+
+ cmds := pipe.Cmds
+ nCmds := len(cmds)
+
+ // If it already has an escaping command, do not interfere.
+ if nCmds != 0 {
+ if lastCmd := cmds[nCmds-1]; len(lastCmd.Args) != 0 {
+ // TODO: Recognize url and js as escaping functions once
+ // we have enough context to know whether additional
+ // escaping is necessary.
+ if arg, ok := lastCmd.Args[0].(*parse.IdentifierNode); ok && arg.Ident == "html" {
+ return
+ }
+ }
+ }
+
+ htmlEscapeCommand := parse.CommandNode{
+ NodeType: parse.NodeCommand,
+ Args: []parse.Node{parse.NewIdentifier("html")},
+ }
+
+ node.Pipe.Cmds = append(node.Pipe.Cmds, &htmlEscapeCommand)
+}
+
+// escapeIfNode recursively escapes the if and then clauses but leaves the
+// condition unchanged.
+func escapeIfNode(node *parse.IfNode) {
+ escapeListNode(node.List)
+ escapeListNode(node.ElseList)
+}
+
+// escapeRangeNode recursively escapes the loop body and else clause but
+// leaves the series unchanged.
+func escapeRangeNode(node *parse.RangeNode) {
+ escapeListNode(node.List)
+ escapeListNode(node.ElseList)
+}
+
+// escapeWithNode recursively escapes the scope body and else clause but
+// leaves the pipeline unchanged.
+func escapeWithNode(node *parse.WithNode) {
+ escapeListNode(node.List)
+ escapeListNode(node.ElseList)
+}
diff --git a/libgo/go/exp/template/html/escape_test.go b/libgo/go/exp/template/html/escape_test.go
new file mode 100644
index 00000000000..345a752a896
--- /dev/null
+++ b/libgo/go/exp/template/html/escape_test.go
@@ -0,0 +1,75 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "template"
+ "testing"
+)
+
+type data struct {
+ F, T bool
+ C, G, H string
+ A, E []string
+}
+
+var testData = data{
+ F: false,
+ T: true,
+ C: "<Cincinatti>",
+ G: "<Goodbye>",
+ H: "<Hello>",
+ A: []string{"<a>", "<b>"},
+ E: []string{},
+}
+
+type testCase struct {
+ name string
+ input string
+ output string
+}
+
+var testCases = []testCase{
+ {"if", "{{if .T}}Hello{{end}}, {{.C}}!", "Hello, &lt;Cincinatti&gt;!"},
+ {"else", "{{if .F}}{{.H}}{{else}}{{.G}}{{end}}!", "&lt;Goodbye&gt;!"},
+ {"overescaping", "Hello, {{.C | html}}!", "Hello, &lt;Cincinatti&gt;!"},
+ {"assignment", "{{if $x := .H}}{{$x}}{{end}}", "&lt;Hello&gt;"},
+ {"withBody", "{{with .H}}{{.}}{{end}}", "&lt;Hello&gt;"},
+ {"withElse", "{{with .E}}{{.}}{{else}}{{.H}}{{end}}", "&lt;Hello&gt;"},
+ {"rangeBody", "{{range .A}}{{.}}{{end}}", "&lt;a&gt;&lt;b&gt;"},
+ {"rangeElse", "{{range .E}}{{.}}{{else}}{{.H}}{{end}}", "&lt;Hello&gt;"},
+ {"nonStringValue", "{{.T}}", "true"},
+ {"constant", `<a href="{{"'str'"}}">`, `<a href="&#39;str&#39;">`},
+}
+
+func TestAutoesc(t *testing.T) {
+ for _, testCase := range testCases {
+ name := testCase.name
+ tmpl := template.New(name)
+ tmpl, err := tmpl.Parse(testCase.input)
+ if err != nil {
+ t.Errorf("%s: failed to parse template: %s", name, err)
+ continue
+ }
+
+ Escape(tmpl)
+
+ buffer := new(bytes.Buffer)
+
+ err = tmpl.Execute(buffer, testData)
+ if err != nil {
+ t.Errorf("%s: template execution failed: %s", name, err)
+ continue
+ }
+
+ output := testCase.output
+ actual := buffer.String()
+ if output != actual {
+ t.Errorf("%s: escaped output: %q != %q",
+ name, output, actual)
+ }
+ }
+}
diff --git a/libgo/go/exp/wingui/winapi.go b/libgo/go/exp/wingui/winapi.go
index c96f452999f..31b57a2cc86 100644
--- a/libgo/go/exp/wingui/winapi.go
+++ b/libgo/go/exp/wingui/winapi.go
@@ -5,26 +5,9 @@
package main
import (
- "syscall"
"unsafe"
)
-func loadDll(fname string) uint32 {
- h, e := syscall.LoadLibrary(fname)
- if e != 0 {
- abortf("LoadLibrary(%s) failed with err=%d.\n", fname, e)
- }
- return h
-}
-
-func getSysProcAddr(m uint32, pname string) uintptr {
- p, e := syscall.GetProcAddress(m, pname)
- if e != 0 {
- abortf("GetProcAddress(%s) failed with err=%d.\n", pname, e)
- }
- return uintptr(p)
-}
-
type Wndclassex struct {
Size uint32
Style uint32
@@ -96,7 +79,7 @@ const (
// Some button control styles
BS_DEFPUSHBUTTON = 1
- // Some colour constants
+ // Some color constants
COLOR_WINDOW = 5
COLOR_BTNFACE = 15
@@ -108,13 +91,13 @@ const (
)
var (
- // Some globaly known cusrors
+ // Some globally known cursors
IDC_ARROW = MakeIntResource(32512)
IDC_IBEAM = MakeIntResource(32513)
IDC_WAIT = MakeIntResource(32514)
IDC_CROSS = MakeIntResource(32515)
- // Some globaly known icons
+ // Some globally known icons
IDI_APPLICATION = MakeIntResource(32512)
IDI_HAND = MakeIntResource(32513)
IDI_QUESTION = MakeIntResource(32514)
diff --git a/libgo/go/exp/wingui/zwinapi.go b/libgo/go/exp/wingui/zwinapi.go
index 6ae6330a1fa..4c009dd69bc 100644
--- a/libgo/go/exp/wingui/zwinapi.go
+++ b/libgo/go/exp/wingui/zwinapi.go
@@ -7,29 +7,29 @@ import "unsafe"
import "syscall"
var (
- modkernel32 = loadDll("kernel32.dll")
- moduser32 = loadDll("user32.dll")
-
- procGetModuleHandleW = getSysProcAddr(modkernel32, "GetModuleHandleW")
- procRegisterClassExW = getSysProcAddr(moduser32, "RegisterClassExW")
- procCreateWindowExW = getSysProcAddr(moduser32, "CreateWindowExW")
- procDefWindowProcW = getSysProcAddr(moduser32, "DefWindowProcW")
- procDestroyWindow = getSysProcAddr(moduser32, "DestroyWindow")
- procPostQuitMessage = getSysProcAddr(moduser32, "PostQuitMessage")
- procShowWindow = getSysProcAddr(moduser32, "ShowWindow")
- procUpdateWindow = getSysProcAddr(moduser32, "UpdateWindow")
- procGetMessageW = getSysProcAddr(moduser32, "GetMessageW")
- procTranslateMessage = getSysProcAddr(moduser32, "TranslateMessage")
- procDispatchMessageW = getSysProcAddr(moduser32, "DispatchMessageW")
- procLoadIconW = getSysProcAddr(moduser32, "LoadIconW")
- procLoadCursorW = getSysProcAddr(moduser32, "LoadCursorW")
- procSetCursor = getSysProcAddr(moduser32, "SetCursor")
- procSendMessageW = getSysProcAddr(moduser32, "SendMessageW")
- procPostMessageW = getSysProcAddr(moduser32, "PostMessageW")
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+ moduser32 = syscall.NewLazyDLL("user32.dll")
+
+ procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
+ procRegisterClassExW = moduser32.NewProc("RegisterClassExW")
+ procCreateWindowExW = moduser32.NewProc("CreateWindowExW")
+ procDefWindowProcW = moduser32.NewProc("DefWindowProcW")
+ procDestroyWindow = moduser32.NewProc("DestroyWindow")
+ procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
+ procShowWindow = moduser32.NewProc("ShowWindow")
+ procUpdateWindow = moduser32.NewProc("UpdateWindow")
+ procGetMessageW = moduser32.NewProc("GetMessageW")
+ procTranslateMessage = moduser32.NewProc("TranslateMessage")
+ procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
+ procLoadIconW = moduser32.NewProc("LoadIconW")
+ procLoadCursorW = moduser32.NewProc("LoadCursorW")
+ procSetCursor = moduser32.NewProc("SetCursor")
+ procSendMessageW = moduser32.NewProc("SendMessageW")
+ procPostMessageW = moduser32.NewProc("PostMessageW")
)
func GetModuleHandle(modname *uint16) (handle uint32, errno int) {
- r0, _, e1 := syscall.Syscall(procGetModuleHandleW, 1, uintptr(unsafe.Pointer(modname)), 0, 0)
+ r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(modname)), 0, 0)
handle = uint32(r0)
if handle == 0 {
if e1 != 0 {
@@ -44,7 +44,7 @@ func GetModuleHandle(modname *uint16) (handle uint32, errno int) {
}
func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) {
- r0, _, e1 := syscall.Syscall(procRegisterClassExW, 1, uintptr(unsafe.Pointer(wndclass)), 0, 0)
+ r0, _, e1 := syscall.Syscall(procRegisterClassExW.Addr(), 1, uintptr(unsafe.Pointer(wndclass)), 0, 0)
atom = uint16(r0)
if atom == 0 {
if e1 != 0 {
@@ -59,7 +59,7 @@ func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) {
}
func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent uint32, menu uint32, instance uint32, param uintptr) (hwnd uint32, errno int) {
- r0, _, e1 := syscall.Syscall12(procCreateWindowExW, 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param))
+ r0, _, e1 := syscall.Syscall12(procCreateWindowExW.Addr(), 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param))
hwnd = uint32(r0)
if hwnd == 0 {
if e1 != 0 {
@@ -74,13 +74,13 @@ func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style
}
func DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) {
- r0, _, _ := syscall.Syscall6(procDefWindowProcW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
+ r0, _, _ := syscall.Syscall6(procDefWindowProcW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
lresult = int32(r0)
return
}
func DestroyWindow(hwnd uint32) (errno int) {
- r1, _, e1 := syscall.Syscall(procDestroyWindow, 1, uintptr(hwnd), 0, 0)
+ r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
errno = int(e1)
@@ -94,18 +94,18 @@ func DestroyWindow(hwnd uint32) (errno int) {
}
func PostQuitMessage(exitcode int32) {
- syscall.Syscall(procPostQuitMessage, 1, uintptr(exitcode), 0, 0)
+ syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitcode), 0, 0)
return
}
func ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) {
- r0, _, _ := syscall.Syscall(procShowWindow, 2, uintptr(hwnd), uintptr(cmdshow), 0)
+ r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0)
wasvisible = bool(r0 != 0)
return
}
func UpdateWindow(hwnd uint32) (errno int) {
- r1, _, e1 := syscall.Syscall(procUpdateWindow, 1, uintptr(hwnd), 0, 0)
+ r1, _, e1 := syscall.Syscall(procUpdateWindow.Addr(), 1, uintptr(hwnd), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
errno = int(e1)
@@ -119,7 +119,7 @@ func UpdateWindow(hwnd uint32) (errno int) {
}
func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) {
- r0, _, e1 := syscall.Syscall6(procGetMessageW, 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0)
+ r0, _, e1 := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0)
ret = int32(r0)
if ret == -1 {
if e1 != 0 {
@@ -134,19 +134,19 @@ func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32)
}
func TranslateMessage(msg *Msg) (done bool) {
- r0, _, _ := syscall.Syscall(procTranslateMessage, 1, uintptr(unsafe.Pointer(msg)), 0, 0)
+ r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
done = bool(r0 != 0)
return
}
func DispatchMessage(msg *Msg) (ret int32) {
- r0, _, _ := syscall.Syscall(procDispatchMessageW, 1, uintptr(unsafe.Pointer(msg)), 0, 0)
+ r0, _, _ := syscall.Syscall(procDispatchMessageW.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
ret = int32(r0)
return
}
func LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) {
- r0, _, e1 := syscall.Syscall(procLoadIconW, 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
+ r0, _, e1 := syscall.Syscall(procLoadIconW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
icon = uint32(r0)
if icon == 0 {
if e1 != 0 {
@@ -161,7 +161,7 @@ func LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) {
}
func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) {
- r0, _, e1 := syscall.Syscall(procLoadCursorW, 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
+ r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
cursor = uint32(r0)
if cursor == 0 {
if e1 != 0 {
@@ -176,7 +176,7 @@ func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int)
}
func SetCursor(cursor uint32) (precursor uint32, errno int) {
- r0, _, e1 := syscall.Syscall(procSetCursor, 1, uintptr(cursor), 0, 0)
+ r0, _, e1 := syscall.Syscall(procSetCursor.Addr(), 1, uintptr(cursor), 0, 0)
precursor = uint32(r0)
if precursor == 0 {
if e1 != 0 {
@@ -191,13 +191,13 @@ func SetCursor(cursor uint32) (precursor uint32, errno int) {
}
func SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) {
- r0, _, _ := syscall.Syscall6(procSendMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
+ r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
lresult = int32(r0)
return
}
func PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (errno int) {
- r1, _, e1 := syscall.Syscall6(procPostMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
+ r1, _, e1 := syscall.Syscall6(procPostMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
errno = int(e1)
diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go
index 7123d4b0f77..7b733faf674 100644
--- a/libgo/go/expvar/expvar.go
+++ b/libgo/go/expvar/expvar.go
@@ -189,7 +189,6 @@ func (f Func) String() string {
return string(v)
}
-
// All published variables.
var vars map[string]Var = make(map[string]Var)
var mutex sync.Mutex
diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go
index 94926d9f8ce..8f7a48168ea 100644
--- a/libgo/go/expvar/expvar_test.go
+++ b/libgo/go/expvar/expvar_test.go
@@ -76,33 +76,33 @@ func TestString(t *testing.T) {
}
func TestMapCounter(t *testing.T) {
- colours := NewMap("bike-shed-colours")
+ colors := NewMap("bike-shed-colors")
- 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)
+ colors.Add("red", 1)
+ colors.Add("red", 2)
+ colors.Add("blue", 4)
+ colors.AddFloat("green", 4.125)
+ if x := colors.m["red"].(*Int).i; x != 3 {
+ t.Errorf("colors.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 := colors.m["blue"].(*Int).i; x != 4 {
+ t.Errorf("colors.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)
+ if x := colors.m["green"].(*Float).f; x != 4.125 {
+ t.Errorf("colors.m[\"green\"] = %v, want 3.14", x)
}
- // colours.String() should be '{"red":3, "blue":4}',
+ // colors.String() should be '{"red":3, "blue":4}',
// though the order of red and blue could vary.
- s := colours.String()
+ s := colors.String()
var j interface{}
err := json.Unmarshal([]byte(s), &j)
if err != nil {
- t.Errorf("colours.String() isn't valid JSON: %v", err)
+ t.Errorf("colors.String() isn't valid JSON: %v", err)
}
m, ok := j.(map[string]interface{})
if !ok {
- t.Error("colours.String() didn't produce a map.")
+ t.Error("colors.String() didn't produce a map.")
}
red := m["red"]
x, ok := red.(float64)
diff --git a/libgo/go/flag/export_test.go b/libgo/go/flag/export_test.go
index b5e3243b310..7b190807a8a 100644
--- a/libgo/go/flag/export_test.go
+++ b/libgo/go/flag/export_test.go
@@ -9,24 +9,14 @@ 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.
+// After calling ResetForTesting, parse errors in flag handling will not
+// exit the program.
func ResetForTesting(usage func()) {
- flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
+ commandLine = NewFlagSet(os.Args[0], ContinueOnError)
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
+// CommandLine returns the default FlagSet.
+func CommandLine() *FlagSet {
+ return commandLine
}
diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go
index 9ed20e06b5a..01bbc377008 100644
--- a/libgo/go/flag/flag.go
+++ b/libgo/go/flag/flag.go
@@ -50,18 +50,12 @@
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.Arg(0)
- switch subcmd {
- // add per-subcommand options
- }
- os.Args = flag.Args()
- flag.Parse()
+ The default set of command-line flags is controlled by
+ top-level functions. The FlagSet type allows one to define
+ independent sets of flags, such as to implement subcommands
+ in a command-line interface. The methods of FlagSet are
+ analogous to the top-level functions for the command-line
+ flag set.
*/
package flag
@@ -72,6 +66,9 @@ import (
"strconv"
)
+// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined.
+var ErrHelp = os.NewError("flag: help requested")
+
// -- Bool Value
type boolValue bool
@@ -190,6 +187,30 @@ type Value interface {
Set(string) bool
}
+// ErrorHandling defines how to handle flag parsing errors.
+type ErrorHandling int
+
+const (
+ ContinueOnError ErrorHandling = iota
+ ExitOnError
+ PanicOnError
+)
+
+// A FlagSet represents a set of defined flags.
+type FlagSet struct {
+ // Usage is the function called when an error occurs while parsing flags.
+ // The field is a function (not a method) that may be changed to point to
+ // a custom error handler.
+ Usage func()
+
+ name string
+ actual map[string]*Flag
+ formal map[string]*Flag
+ args []string // arguments after flags
+ exitOnError bool // does the program exit if there's an error?
+ errorHandling ErrorHandling
+}
+
// A Flag represents the state of a flag.
type Flag struct {
Name string // name as it appears on command line
@@ -198,17 +219,9 @@ type Flag struct {
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
-
// sortFlags returns the flags as a slice in lexicographical sorted order.
func sortFlags(flags map[string]*Flag) []*Flag {
- list := make(sort.StringArray, len(flags))
+ list := make(sort.StringSlice, len(flags))
i := 0
for _, f := range flags {
list[i] = f.Name
@@ -224,43 +237,67 @@ func sortFlags(flags map[string]*Flag) []*Flag {
// VisitAll visits the flags in lexicographical order, calling fn for each.
// It visits all flags, even those not set.
-func VisitAll(fn func(*Flag)) {
- for _, f := range sortFlags(flags.formal) {
- fn(f)
+func (f *FlagSet) VisitAll(fn func(*Flag)) {
+ for _, flag := range sortFlags(f.formal) {
+ fn(flag)
}
}
+// VisitAll visits the command-line flags in lexicographical order, calling
+// fn for each. It visits all flags, even those not set.
+func VisitAll(fn func(*Flag)) {
+ commandLine.VisitAll(fn)
+}
+
// Visit visits the flags in lexicographical order, calling fn for each.
// It visits only those flags that have been set.
-func Visit(fn func(*Flag)) {
- for _, f := range sortFlags(flags.actual) {
- fn(f)
+func (f *FlagSet) Visit(fn func(*Flag)) {
+ for _, flag := range sortFlags(f.actual) {
+ fn(flag)
}
}
+// Visit visits the command-line flags in lexicographical order, calling fn
+// for each. It visits only those flags that have been set.
+func Visit(fn func(*Flag)) {
+ commandLine.Visit(fn)
+}
+
// Lookup returns the Flag structure of the named flag, returning nil if none exists.
+func (f *FlagSet) Lookup(name string) *Flag {
+ return f.formal[name]
+}
+
+// Lookup returns the Flag structure of the named command-line flag,
+// returning nil if none exists.
func Lookup(name string) *Flag {
- return flags.formal[name]
+ return commandLine.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]
+func (f *FlagSet) Set(name, value string) bool {
+ flag, ok := f.formal[name]
if !ok {
return false
}
- ok = f.Value.Set(value)
+ ok = flag.Value.Set(value)
if !ok {
return false
}
- flags.actual[name] = f
+ f.actual[name] = flag
return true
}
-// PrintDefaults prints to standard error the default values of all defined flags.
-func PrintDefaults() {
- VisitAll(func(f *Flag) {
+// Set sets the value of the named command-line flag. It returns true if the
+// set succeeded; false if there is no such flag defined.
+func Set(name, value string) bool {
+ return commandLine.Set(name, value)
+}
+
+// PrintDefaults prints to standard error the default values of all defined flags in the set.
+func (f *FlagSet) PrintDefaults() {
+ f.VisitAll(func(f *Flag) {
format := " -%s=%s: %s\n"
if _, ok := f.Value.(*stringValue); ok {
// put quotes on the value
@@ -270,174 +307,304 @@ func PrintDefaults() {
})
}
-// Usage prints to standard error a default usage message documenting all defined flags.
+// PrintDefaults prints to standard error the default values of all defined command-line flags.
+func PrintDefaults() {
+ commandLine.PrintDefaults()
+}
+
+// defaultUsage is the default function to print a usage message.
+func defaultUsage(f *FlagSet) {
+ fmt.Fprintf(os.Stderr, "Usage of %s:\n", f.name)
+ f.PrintDefaults()
+}
+
+// Usage prints to standard error a usage message documenting all defined command-line 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()
+ defaultUsage(commandLine)
}
-var panicOnError = false
+// NFlag returns the number of flags that have been set.
+func (f *FlagSet) NFlag() int { return len(f.actual) }
-// failf prints to standard error a formatted error and Usage, and then exits the program.
-func failf(format string, a ...interface{}) {
- fmt.Fprintf(os.Stderr, format, a...)
- Usage()
- if panicOnError {
- panic("flag parse error")
+// NFlag returns the number of command-line flags that have been set.
+func NFlag() int { return len(commandLine.actual) }
+
+// Arg returns the i'th argument. Arg(0) is the first remaining argument
+// after flags have been processed.
+func (f *FlagSet) Arg(i int) string {
+ if i < 0 || i >= len(f.args) {
+ return ""
}
- os.Exit(2)
+ return f.args[i]
}
-// NFlag returns the number of flags that have been set.
-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]
+ return commandLine.Arg(i)
}
// NArg is the number of arguments remaining after flags have been processed.
-func NArg() int { return len(flags.args) }
+func (f *FlagSet) NArg() int { return len(f.args) }
+
+// NArg is the number of arguments remaining after flags have been processed.
+func NArg() int { return len(commandLine.args) }
+
+// Args returns the non-flag arguments.
+func (f *FlagSet) Args() []string { return f.args }
// Args returns the non-flag command-line arguments.
-func Args() []string { return flags.args }
+func Args() []string { return commandLine.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 (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
+ f.Var(newBoolValue(value, p), name, usage)
+}
// 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)
+ commandLine.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 {
+func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
p := new(bool)
- BoolVar(p, name, value, usage)
+ f.BoolVar(p, name, value, usage)
return p
}
+// 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 {
+ return commandLine.Bool(name, value, usage)
+}
+
+// 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 (f *FlagSet) IntVar(p *int, name string, value int, usage string) {
+ f.Var(newIntValue(value, p), name, usage)
+}
+
// 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)
+ commandLine.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 {
+func (f *FlagSet) Int(name string, value int, usage string) *int {
p := new(int)
- IntVar(p, name, value, usage)
+ f.IntVar(p, name, value, usage)
return p
}
+// 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 {
+ return commandLine.Int(name, value, usage)
+}
+
+// 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 (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) {
+ f.Var(newInt64Value(value, p), name, usage)
+}
+
// 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)
+ commandLine.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 {
+func (f *FlagSet) Int64(name string, value int64, usage string) *int64 {
p := new(int64)
- Int64Var(p, name, value, usage)
+ f.Int64Var(p, name, value, usage)
return p
}
+// 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 {
+ return commandLine.Int64(name, value, usage)
+}
+
// 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 (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) {
+ f.Var(newUintValue(value, p), name, usage)
+}
+
+// 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)
+ commandLine.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 {
+// The return value is the address of a uint variable that stores the value of the flag.
+func (f *FlagSet) Uint(name string, value uint, usage string) *uint {
p := new(uint)
- UintVar(p, name, value, usage)
+ f.UintVar(p, name, value, usage)
return p
}
+// 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 {
+ return commandLine.Uint(name, value, usage)
+}
+
+// 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 (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) {
+ f.Var(newUint64Value(value, p), name, usage)
+}
+
// 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)
+ commandLine.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 {
+func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 {
p := new(uint64)
- Uint64Var(p, name, value, usage)
+ f.Uint64Var(p, name, value, usage)
return p
}
+// 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 {
+ return commandLine.Uint64(name, value, usage)
+}
+
+// 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 (f *FlagSet) StringVar(p *string, name string, value string, usage string) {
+ f.Var(newStringValue(value, p), name, usage)
+}
+
// 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)
+func StringVar(p *string, name string, value string, usage string) {
+ commandLine.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 {
+func (f *FlagSet) String(name string, value string, usage string) *string {
p := new(string)
- StringVar(p, name, value, usage)
+ f.StringVar(p, name, value, usage)
return p
}
+// 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 string, value string, usage string) *string {
+ return commandLine.String(name, value, usage)
+}
+
+// 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 (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) {
+ f.Var(newFloat64Value(value, p), name, usage)
+}
+
// 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)
+ commandLine.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 {
+func (f *FlagSet) Float64(name string, value float64, usage string) *float64 {
p := new(float64)
- Float64Var(p, name, value, usage)
+ f.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) {
+// Float64 defines an int 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 {
+ return commandLine.Float64(name, value, usage)
+}
+
+// Var defines a flag with the specified name and usage string. The type and
+// value of the flag are represented by the first argument, of type Value, which
+// typically holds a user-defined implementation of Value. For instance, the
+// caller could create a flag that turns a comma-separated string into a slice
+// of strings by giving the slice the methods of Value; in particular, Set would
+// decompose the comma-separated string into the slice.
+func (f *FlagSet) 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]
+ flag := &Flag{name, usage, value, value.String()}
+ _, alreadythere := f.formal[name]
if alreadythere {
- fmt.Fprintln(os.Stderr, "flag redefined:", name)
+ fmt.Fprintf(os.Stderr, "%s flag redefined: %s\n", f.name, name)
panic("flag redefinition") // Happens only if flags are declared with identical names
}
- flags.formal[name] = f
+ f.formal[name] = flag
+}
+
+// Var defines a flag with the specified name and usage string. The type and
+// value of the flag are represented by the first argument, of type Value, which
+// typically holds a user-defined implementation of Value. For instance, the
+// caller could create a flag that turns a comma-separated string into a slice
+// of strings by giving the slice the methods of Value; in particular, Set would
+// decompose the comma-separated string into the slice.
+func Var(value Value, name string, usage string) {
+ commandLine.Var(value, name, usage)
+}
+
+// failf prints to standard error a formatted error and usage message and
+// returns the error.
+func (f *FlagSet) failf(format string, a ...interface{}) os.Error {
+ err := fmt.Errorf(format, a...)
+ fmt.Fprintln(os.Stderr, err)
+ f.usage()
+ return err
}
+// usage calls the Usage method for the flag set, or the usage function if
+// the flag set is commandLine.
+func (f *FlagSet) usage() {
+ if f == commandLine {
+ Usage()
+ } else {
+ f.Usage()
+ }
+}
-func (f *allFlags) parseOne() (ok bool) {
+// parseOne parses one flag. It returns whether a flag was seen.
+func (f *FlagSet) parseOne() (bool, os.Error) {
if len(f.args) == 0 {
- return false
+ return false, nil
}
s := f.args[0]
if len(s) == 0 || s[0] != '-' || len(s) == 1 {
- return false
+ return false, nil
}
num_minuses := 1
if s[1] == '-' {
num_minuses++
if len(s) == 2 { // "--" terminates the flags
f.args = f.args[1:]
- return false
+ return false, nil
}
}
name := s[num_minuses:]
if len(name) == 0 || name[0] == '-' || name[0] == '=' {
- failf("bad flag syntax: %s\n", s)
+ return false, f.failf("bad flag syntax: %s", s)
}
// it's a flag. does it have an argument?
@@ -452,15 +619,19 @@ func (f *allFlags) parseOne() (ok bool) {
break
}
}
- m := flags.formal
+ m := f.formal
flag, alreadythere := m[name] // BUG
if !alreadythere {
- failf("flag provided but not defined: -%s\n", name)
+ if name == "help" || name == "h" { // special case for nice help message.
+ f.usage()
+ return false, ErrHelp
+ }
+ return false, f.failf("flag provided but not defined: -%s", name)
}
if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
if has_value {
if !fv.Set(value) {
- failf("invalid boolean value %q for flag: -%s\n", value, name)
+ f.failf("invalid boolean value %q for flag: -%s", value, name)
}
} else {
fv.Set("true")
@@ -473,25 +644,62 @@ func (f *allFlags) parseOne() (ok bool) {
value, f.args = f.args[0], f.args[1:]
}
if !has_value {
- failf("flag needs an argument: -%s\n", name)
+ return false, f.failf("flag needs an argument: -%s", name)
}
ok = flag.Value.Set(value)
if !ok {
- failf("invalid value %q for flag: -%s\n", value, name)
+ return false, f.failf("invalid value %q for flag: -%s", value, name)
}
}
- flags.actual[name] = flag
- return true
+ f.actual[name] = flag
+ return true, nil
+}
+
+// Parse parses flag definitions from the argument list, which should not
+// include the command name. Must be called after all flags in the FlagSet
+// are defined and before flags are accessed by the program.
+// The return value will be ErrHelp if -help was set but not defined.
+func (f *FlagSet) Parse(arguments []string) os.Error {
+ f.args = arguments
+ for {
+ seen, err := f.parseOne()
+ if seen {
+ continue
+ }
+ if err == nil {
+ break
+ }
+ switch f.errorHandling {
+ case ContinueOnError:
+ return err
+ case ExitOnError:
+ os.Exit(2)
+ case PanicOnError:
+ panic(err)
+ }
+ }
+ return nil
}
-// Parse parses the command-line flags. Must be called after all flags are defined
-// and before any are accessed by the program.
+// Parse parses the command-line flags from os.Args[1:]. Must be called
+// after all flags are defined and before flags are accessed by the program.
func Parse() {
- flags.args = os.Args[1:]
- for flags.parseOne() {
- }
+ // Ignore errors; commandLine is set for ExitOnError.
+ commandLine.Parse(os.Args[1:])
}
-func init() {
- flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
+// The default set of command-line flags, parsed from os.Args.
+var commandLine = NewFlagSet(os.Args[0], ExitOnError)
+
+// NewFlagSet returns a new, empty flag set with the specified name and
+// error handling property.
+func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
+ f := &FlagSet{
+ name: name,
+ actual: make(map[string]*Flag),
+ formal: make(map[string]*Flag),
+ errorHandling: errorHandling,
+ }
+ f.Usage = func() { defaultUsage(f) }
+ return f
}
diff --git a/libgo/go/flag/flag_test.go b/libgo/go/flag/flag_test.go
index 1e47d12e48a..63d0a9fc894 100644
--- a/libgo/go/flag/flag_test.go
+++ b/libgo/go/flag/flag_test.go
@@ -89,7 +89,7 @@ func TestEverything(t *testing.T) {
func TestUsage(t *testing.T) {
called := false
ResetForTesting(func() { called = true })
- if ParseForTesting([]string{"a.out", "-x"}) {
+ if CommandLine().Parse([]string{"-x"}) == nil {
t.Error("parse did not fail for unknown flag")
}
if !called {
@@ -97,19 +97,17 @@ func TestUsage(t *testing.T) {
}
}
-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")
+func testParse(f *FlagSet, t *testing.T) {
+ boolFlag := f.Bool("bool", false, "bool value")
+ bool2Flag := f.Bool("bool2", false, "bool2 value")
+ intFlag := f.Int("int", 0, "int value")
+ int64Flag := f.Int64("int64", 0, "int64 value")
+ uintFlag := f.Uint("uint", 0, "uint value")
+ uint64Flag := f.Uint64("uint64", 0, "uint64 value")
+ stringFlag := f.String("string", "0", "string value")
+ float64Flag := f.Float64("float64", 0, "float64 value")
extra := "one-extra-argument"
args := []string{
- "a.out",
"-bool",
"-bool2=true",
"--int", "22",
@@ -120,8 +118,8 @@ func TestParse(t *testing.T) {
"-float64", "2718e28",
extra,
}
- if !ParseForTesting(args) {
- t.Fatal("parse failed")
+ if err := f.Parse(args); err != nil {
+ t.Fatal(err)
}
if *boolFlag != true {
t.Error("bool flag should be true, is ", *boolFlag)
@@ -147,14 +145,23 @@ func TestParse(t *testing.T) {
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])
+ if len(f.Args()) != 1 {
+ t.Error("expected one argument, got", len(f.Args()))
+ } else if f.Args()[0] != extra {
+ t.Errorf("expected argument %q got %q", extra, f.Args()[0])
}
}
-// Declare a user-defined flag.
+func TestParse(t *testing.T) {
+ ResetForTesting(func() { t.Error("bad parse") })
+ testParse(CommandLine(), t)
+}
+
+func TestFlagSetParse(t *testing.T) {
+ testParse(NewFlagSet("test", ContinueOnError), t)
+}
+
+// Declare a user-defined flag type.
type flagVar []string
func (f *flagVar) String() string {
@@ -167,11 +174,11 @@ func (f *flagVar) Set(value string) bool {
}
func TestUserDefined(t *testing.T) {
- ResetForTesting(func() { t.Fatal("bad parse") })
+ flags := NewFlagSet("test", ContinueOnError)
var v flagVar
- Var(&v, "v", "usage")
- if !ParseForTesting([]string{"a.out", "-v", "1", "-v", "2", "-v=3"}) {
- t.Error("parse failed")
+ flags.Var(&v, "v", "usage")
+ if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil {
+ t.Error(err)
}
if len(v) != 3 {
t.Fatal("expected 3 args; got ", len(v))
@@ -182,13 +189,17 @@ func TestUserDefined(t *testing.T) {
}
}
+// This tests that one can reset the flags. This still works but not well, and is
+// superseded by FlagSet.
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()
+ if err := CommandLine().Parse(os.Args[1:]); err != nil {
+ t.Fatal(err)
+ }
cmd := Arg(0)
os.Args = Args()
after := Bool("after", false, "")
@@ -199,3 +210,46 @@ func TestChangingArgs(t *testing.T) {
t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
}
}
+
+// Test that -help invokes the usage message and returns ErrHelp.
+func TestHelp(t *testing.T) {
+ var helpCalled = false
+ fs := NewFlagSet("help test", ContinueOnError)
+ fs.Usage = func() { helpCalled = true }
+ var flag bool
+ fs.BoolVar(&flag, "flag", false, "regular flag")
+ // Regular flag invocation should work
+ err := fs.Parse([]string{"-flag=true"})
+ if err != nil {
+ t.Fatal("expected no error; got ", err)
+ }
+ if !flag {
+ t.Error("flag was not set by -flag")
+ }
+ if helpCalled {
+ t.Error("help called for regular flag")
+ helpCalled = false // reset for next test
+ }
+ // Help flag should work as expected.
+ err = fs.Parse([]string{"-help"})
+ if err == nil {
+ t.Fatal("error expected")
+ }
+ if err != ErrHelp {
+ t.Fatal("expected ErrHelp; got ", err)
+ }
+ if !helpCalled {
+ t.Fatal("help was not called")
+ }
+ // If we define a help flag, that should override.
+ var help bool
+ fs.BoolVar(&help, "help", false, "help flag")
+ helpCalled = false
+ err = fs.Parse([]string{"-help"})
+ if err != nil {
+ t.Fatal("expected no error for defined -help; got ", err)
+ }
+ if helpCalled {
+ t.Fatal("help was called; should not have been for defined help flag")
+ }
+}
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go
index e4d4f184427..35a11e19fa1 100644
--- a/libgo/go/fmt/doc.go
+++ b/libgo/go/fmt/doc.go
@@ -25,9 +25,10 @@
%c the character represented by the corresponding Unicode code point
%d base 10
%o base 8
+ %q a single-quoted character literal safely escaped with Go syntax.
%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+%0.4X"
+ %U Unicode format: U+1234; same as "U+%04X"
Floating-point and complex constituents:
%b decimalless scientific notation with exponent a power
of two, in the manner of strconv.Ftoa32, e.g. -123456p-78
@@ -62,11 +63,13 @@
number of characters to output, truncating if necessary.
Other flags:
- + always print a sign for numeric values
+ + always print a sign for numeric values;
+ guarantee ASCII-only output for %q (%+q)
- pad with spaces on the right rather than the left (left-justify the field)
# alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
0X for hex (%#X); suppress 0x for %p (%#p);
- print a raw (backquoted) string if possible for %q (%#q)
+ print a raw (backquoted) string if possible for %q (%#q);
+ write e.g. U+0078 'x' if the character is printable for %U (%#U).
' ' (space) leave a space for elided sign in numbers (% d);
put spaces between bytes printing strings or slices in hex (% x, % X)
0 pad with leading zeros rather than spaces
@@ -134,10 +137,10 @@
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
+ %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
The familiar base-setting prefixes 0 (octal) and 0x
(hexadecimal) are accepted when scanning integers without a
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index b3c0c5abed4..1142c9f8ad7 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -43,7 +43,6 @@ func TestFmtInterface(t *testing.T) {
}
}
-
const b32 uint32 = 1<<32 - 1
const b64 uint64 = 1<<64 - 1
@@ -132,12 +131,26 @@ var fmttests = []struct {
{"%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", "\u263a", `"☺"`},
+ {"%+q", "\u263a", `"\u263a"`},
{"%q", "\U0010ffff", `"\U0010ffff"`},
+ // escaped characters
+ {"%q", 'x', `'x'`},
+ {"%q", 0, `'\x00'`},
+ {"%q", '\n', `'\n'`},
+ {"%q", '\u0e00', `'\u0e00'`}, // not a printable rune.
+ {"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune.
+ {"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`},
+ {"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
+ {"%q", '"', `'"'`},
+ {"%q", '\'', `'\''`},
+ {"%q", "\u263a", `"☺"`},
+ {"%+q", "\u263a", `"\u263a"`},
+
// width
{"%5s", "abc", " abc"},
- {"%2s", "\u263a", " \u263a"},
+ {"%2s", "\u263a", " ☺"},
{"%-5s", "abc", "abc "},
{"%-8q", "abc", `"abc" `},
{"%05s", "abc", "00abc"},
@@ -147,9 +160,9 @@ var fmttests = []struct {
{"%.5s", "日本語日本語", "日本語日本"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
- {"%.3q", "日本語日本語", `"\u65e5\u672c\u8a9e"`},
- {"%.3q", []byte("日本語日本語"), `"\u65e5\u672c\u8a9e"`},
- {"%10.1q", "日本語日本語", ` "\u65e5"`},
+ {"%.3q", "日本語日本語", `"日本語"`},
+ {"%.3q", []byte("日本語日本語"), `"日本語"`},
+ {"%10.1q", "日本語日本語", ` "日"`},
// integers
{"%d", 12345, "12345"},
@@ -167,6 +180,8 @@ var fmttests = []struct {
{"%+d", 0, "+0"},
{"% d", 0, " 0"},
{"% d", 12345, " 12345"},
+ {"%.0d", 0, ""},
+ {"%.d", 0, ""},
// unicode format
{"%U", 0x1, "U+0001"},
@@ -176,6 +191,12 @@ var fmttests = []struct {
{"%U", 0x12345, "U+12345"},
{"%10.6U", 0xABC, " U+000ABC"},
{"%-10.6U", 0xABC, "U+000ABC "},
+ {"%U", '\n', `U+000A`},
+ {"%#U", '\n', `U+000A`},
+ {"%U", 'x', `U+0078`},
+ {"%#U", 'x', `U+0078 'x'`},
+ {"%U", '\u263a', `U+263A`},
+ {"%#U", '\u263a', `U+263A '☺'`},
// floats
{"%+.3e", 0.0, "+0.000e+00"},
@@ -456,28 +477,36 @@ func TestCountMallocs(t *testing.T) {
if testing.Short() {
return
}
+ runtime.UpdateMemStats()
mallocs := 0 - runtime.MemStats.Mallocs
for i := 0; i < 100; i++ {
Sprintf("")
}
+ runtime.UpdateMemStats()
mallocs += runtime.MemStats.Mallocs
Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/100)
+ runtime.UpdateMemStats()
mallocs = 0 - runtime.MemStats.Mallocs
for i := 0; i < 100; i++ {
Sprintf("xxx")
}
+ runtime.UpdateMemStats()
mallocs += runtime.MemStats.Mallocs
Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/100)
+ runtime.UpdateMemStats()
mallocs = 0 - runtime.MemStats.Mallocs
for i := 0; i < 100; i++ {
Sprintf("%x", i)
}
+ runtime.UpdateMemStats()
mallocs += runtime.MemStats.Mallocs
Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/100)
+ runtime.UpdateMemStats()
mallocs = 0 - runtime.MemStats.Mallocs
for i := 0; i < 100; i++ {
Sprintf("%x %x", i, i)
}
+ runtime.UpdateMemStats()
mallocs += runtime.MemStats.Mallocs
Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100)
}
@@ -614,7 +643,6 @@ func TestBlankln(t *testing.T) {
}
}
-
// Check Formatter with Sprint, Sprintln, Sprintf
func TestFormatterPrintln(t *testing.T) {
f := F(1)
@@ -663,3 +691,56 @@ func TestWidthAndPrecision(t *testing.T) {
}
}
}
+
+// A type that panics in String.
+type Panic struct {
+ message interface{}
+}
+
+// Value receiver.
+func (p Panic) GoString() string {
+ panic(p.message)
+}
+
+// Value receiver.
+func (p Panic) String() string {
+ panic(p.message)
+}
+
+// A type that panics in Format.
+type PanicF struct {
+ message interface{}
+}
+
+// Value receiver.
+func (p PanicF) Format(f State, c int) {
+ panic(p.message)
+}
+
+var panictests = []struct {
+ fmt string
+ in interface{}
+ out string
+}{
+ // String
+ {"%d", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%d", Panic{io.ErrUnexpectedEOF}, "%d(PANIC=unexpected EOF)"},
+ {"%d", Panic{3}, "%d(PANIC=3)"},
+ // GoString
+ {"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"},
+ {"%#v", Panic{3}, "%v(PANIC=3)"},
+ // Format
+ {"%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
+ {"%s", PanicF{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"},
+ {"%s", PanicF{3}, "%s(PANIC=3)"},
+}
+
+func TestPanics(t *testing.T) {
+ for _, tt := range panictests {
+ s := Sprintf(tt.fmt, tt.in)
+ if s != tt.out {
+ t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
index f9d2b4fcaf6..24b15a286b7 100644
--- a/libgo/go/fmt/format.go
+++ b/libgo/go/fmt/format.go
@@ -7,6 +7,7 @@ package fmt
import (
"bytes"
"strconv"
+ "unicode"
"utf8"
)
@@ -50,6 +51,7 @@ type fmt struct {
sharp bool
space bool
unicode bool
+ uniQuote bool // Use 'x'= prefix for %U if printable.
zero bool
}
@@ -63,6 +65,7 @@ func (f *fmt) clearflags() {
f.sharp = false
f.space = false
f.unicode = false
+ f.uniQuote = false
f.zero = false
}
@@ -163,6 +166,11 @@ func (f *fmt) fmt_boolean(v bool) {
// 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) {
+ // precision of 0 and value of 0 means "print nothing"
+ if f.precPresent && f.prec == 0 && a == 0 {
+ return
+ }
+
var buf []byte = f.intbuf[0:]
negative := signedness == signed && a < 0
if negative {
@@ -232,6 +240,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
i--
buf[i] = ' '
}
+
+ // If we want a quoted char for %#U, move the data up to make room.
+ if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(int(a)) {
+ runeWidth := utf8.RuneLen(int(a))
+ width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
+ copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
+ i -= width
+ // Now put " 'x'" at the end.
+ j := len(buf) - width
+ buf[j] = ' '
+ j++
+ buf[j] = '\''
+ j++
+ utf8.EncodeRune(buf[j:], int(a))
+ j += runeWidth
+ buf[j] = '\''
+ }
+
f.pad(buf[i:])
}
@@ -291,7 +317,23 @@ func (f *fmt) fmt_q(s string) {
if f.sharp && strconv.CanBackquote(s) {
quoted = "`" + s + "`"
} else {
- quoted = strconv.Quote(s)
+ if f.plus {
+ quoted = strconv.QuoteToASCII(s)
+ } else {
+ quoted = strconv.Quote(s)
+ }
+ }
+ f.padString(quoted)
+}
+
+// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
+// If the character is not valid Unicode, it will print '\ufffd'.
+func (f *fmt) fmt_qc(c int64) {
+ var quoted string
+ if f.plus {
+ quoted = strconv.QuoteRuneToASCII(int(c))
+ } else {
+ quoted = strconv.QuoteRune(int(c))
}
f.padString(quoted)
}
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index 10e0fe7c85b..73873490807 100644
--- a/libgo/go/fmt/print.go
+++ b/libgo/go/fmt/print.go
@@ -9,6 +9,7 @@ import (
"io"
"os"
"reflect"
+ "unicode"
"utf8"
)
@@ -21,6 +22,7 @@ var (
nilBytes = []byte("nil")
mapBytes = []byte("map[")
missingBytes = []byte("(MISSING)")
+ panicBytes = []byte("(PANIC=")
extraBytes = []byte("%!(EXTRA ")
irparenBytes = []byte("i)")
bytesBytes = []byte("[]byte{")
@@ -41,7 +43,7 @@ type State interface {
Precision() (prec int, ok bool)
// Flag returns whether the flag c, a character, has been set.
- Flag(int) bool
+ Flag(c int) bool
}
// Formatter is the interface implemented by values with a custom formatter.
@@ -51,7 +53,7 @@ type Formatter interface {
Format(f State, c int)
}
-// Stringer is implemented by any value that has a String method(),
+// 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.
@@ -59,7 +61,7 @@ type Stringer interface {
String() string
}
-// GoStringer is implemented by any value that has a GoString() method,
+// 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.
@@ -68,10 +70,11 @@ type GoStringer interface {
}
type pp struct {
- n int
- buf bytes.Buffer
- runeBuf [utf8.UTFMax]byte
- fmt fmt
+ n int
+ panicking bool
+ buf bytes.Buffer
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
}
// A cache holds a set of reusable objects.
@@ -110,6 +113,7 @@ var ppFree = newCache(func() interface{} { return new(pp) })
// Allocate a new pp struct or grab a cached one.
func newPrinter() *pp {
p := ppFree.get().(*pp)
+ p.panicking = false
p.fmt.init(&p.buf)
return p
}
@@ -158,19 +162,18 @@ func (p *pp) Write(b []byte) (ret int, err os.Error) {
// 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) {
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) {
p := newPrinter()
p.doPrintf(format, a)
- n64, error := p.buf.WriteTo(w)
+ n64, err := p.buf.WriteTo(w)
p.free()
- return int(n64), error
+ return int(n64), err
}
// 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
+func Printf(format string, a ...interface{}) (n int, err os.Error) {
+ return Fprintf(os.Stdout, format, a...)
}
// Sprintf formats according to a format specifier and returns the resulting string.
@@ -185,7 +188,7 @@ func Sprintf(format string, a ...interface{}) string {
// Errorf formats according to a format specifier and returns the string
// converted to an os.ErrorString, which satisfies the os.Error interface.
func Errorf(format string, a ...interface{}) os.Error {
- return os.ErrorString(Sprintf(format, a...))
+ return os.NewError(Sprintf(format, a...))
}
// These routines do not take a format string
@@ -193,20 +196,19 @@ func Errorf(format string, a ...interface{}) os.Error {
// 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) {
+func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) {
p := newPrinter()
p.doPrint(a, false, false)
- n64, error := p.buf.WriteTo(w)
+ n64, err := p.buf.WriteTo(w)
p.free()
- return int(n64), error
+ return int(n64), err
}
// 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
+func Print(a ...interface{}) (n int, err os.Error) {
+ return Fprint(os.Stdout, a...)
}
// Sprint formats using the default formats for its operands and returns the resulting string.
@@ -226,20 +228,19 @@ func Sprint(a ...interface{}) string {
// 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) {
+func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) {
p := newPrinter()
p.doPrint(a, true, true)
- n64, error := p.buf.WriteTo(w)
+ n64, err := p.buf.WriteTo(w)
p.free()
- return int(n64), error
+ return int(n64), err
}
// 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
+func Println(a ...interface{}) (n int, err os.Error) {
+ return Fprintln(os.Stdout, a...)
}
// Sprintln formats using the default formats for its operands and returns the resulting string.
@@ -252,7 +253,6 @@ func Sprintln(a ...interface{}) string {
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.
@@ -332,6 +332,12 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
p.fmt.integer(v, 10, signed, ldigits)
case 'o':
p.fmt.integer(v, 8, signed, ldigits)
+ case 'q':
+ if 0 <= v && v <= unicode.MaxRune {
+ p.fmt.fmt_qc(v)
+ } else {
+ p.badVerb(verb, value)
+ }
case 'x':
p.fmt.integer(v, 16, signed, ldigits)
case 'U':
@@ -356,6 +362,8 @@ func (p *pp) fmt0x64(v uint64, leading0x bool) {
// temporarily turning on the unicode flag and tweaking the precision.
func (p *pp) fmtUnicode(v int64) {
precPresent := p.fmt.precPresent
+ sharp := p.fmt.sharp
+ p.fmt.sharp = false
prec := p.fmt.prec
if !precPresent {
// If prec is already set, leave it alone; otherwise 4 is minimum.
@@ -363,10 +371,13 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.precPresent = true
}
p.fmt.unicode = true // turn on U+
+ p.fmt.uniQuote = sharp
p.fmt.integer(int64(v), 16, unsigned, udigits)
p.fmt.unicode = false
+ p.fmt.uniQuote = false
p.fmt.prec = prec
p.fmt.precPresent = precPresent
+ p.fmt.sharp = sharp
}
func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
@@ -385,6 +396,12 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
}
case 'o':
p.fmt.integer(int64(v), 8, unsigned, ldigits)
+ case 'q':
+ if 0 <= v && v <= unicode.MaxRune {
+ p.fmt.fmt_qc(int64(v))
+ } else {
+ p.badVerb(verb, value)
+ }
case 'x':
p.fmt.integer(int64(v), 16, unsigned, ldigits)
case 'X':
@@ -548,6 +565,31 @@ var (
uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
)
+func (p *pp) catchPanic(val interface{}, verb int) {
+ if err := recover(); err != nil {
+ // If it's a nil pointer, just say "<nil>". The likeliest causes are a
+ // Stringer that fails to guard against nil or a nil pointer for a
+ // value receiver, and in either case, "<nil>" is a nice result.
+ if v := reflect.ValueOf(val); v.Kind() == reflect.Ptr && v.IsNil() {
+ p.buf.Write(nilAngleBytes)
+ return
+ }
+ // Otherwise print a concise panic message. Most of the time the panic
+ // value will print itself nicely.
+ if p.panicking {
+ // Nested panics; the recursion in printField cannot succeed.
+ panic(err)
+ }
+ p.buf.WriteByte('%')
+ p.add(verb)
+ p.buf.Write(panicBytes)
+ p.panicking = true
+ p.printField(err, 'v', false, false, 0)
+ p.panicking = false
+ p.buf.WriteByte(')')
+ }
+}
+
func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
if field == nil {
if verb == 'T' || verb == 'v' {
@@ -570,6 +612,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
}
// Is it a Formatter?
if formatter, ok := field.(Formatter); ok {
+ defer p.catchPanic(field, verb)
formatter.Format(p, verb)
return false // this value is not a string
@@ -582,6 +625,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
if goSyntax {
p.fmt.sharp = false
if stringer, ok := field.(GoStringer); ok {
+ defer p.catchPanic(field, verb)
// Print the result of GoString unadorned.
p.fmtString(stringer.GoString(), 's', false, field)
return false // this value is not a string
@@ -589,6 +633,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
} else {
// Is it a Stringer?
if stringer, ok := field.(Stringer); ok {
+ defer p.catchPanic(field, verb)
p.printField(stringer.String(), verb, plus, false, depth)
return false // this value is not a string
}
@@ -883,6 +928,10 @@ func (p *pp) doPrintf(format string, a []interface{}) {
}
} else {
p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+ if !p.fmt.precPresent {
+ p.fmt.prec = 0
+ p.fmt.precPresent = true
+ }
}
}
if i >= end {
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
index 42bc52c92bc..259451d02f7 100644
--- a/libgo/go/fmt/scan.go
+++ b/libgo/go/fmt/scan.go
@@ -35,6 +35,10 @@ type ScanState interface {
ReadRune() (rune int, size int, err os.Error)
// UnreadRune causes the next call to ReadRune to return the same rune.
UnreadRune() os.Error
+ // SkipSpace skips space in the input. Newlines are treated as space
+ // unless the scan operation is Scanln, Fscanln or Sscanln, in which case
+ // a newline is treated as EOF.
+ SkipSpace()
// Token skips space in the input if skipSpace is true, then returns the
// run of Unicode code points c satisfying f(c). If f is nil,
// !unicode.IsSpace(c) is used; that is, the token will hold non-space
@@ -167,7 +171,7 @@ type ssave struct {
// satisfies io.Reader. It will never be called when used as
// intended, so there is no need to make it actually work.
func (s *ss) Read(buf []byte) (n int, err os.Error) {
- return 0, os.ErrorString("ScanState's Read should not be called. Use ReadRune")
+ return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
}
func (s *ss) ReadRune() (rune int, size int, err os.Error) {
@@ -231,6 +235,7 @@ func (s *ss) UnreadRune() os.Error {
} else {
s.peekRune = s.prevRune
}
+ s.prevRune = -1
s.count--
return nil
}
@@ -240,7 +245,7 @@ func (s *ss) error(err os.Error) {
}
func (s *ss) errorString(err string) {
- panic(scanError{os.ErrorString(err)})
+ panic(scanError{os.NewError(err)})
}
func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
@@ -266,6 +271,12 @@ func notSpace(r int) bool {
return !unicode.IsSpace(r)
}
+// skipSpace provides Scan() methods the ability to skip space and newline characters
+// in keeping with the current scanning mode set by format strings and Scan()/Scanln().
+func (s *ss) SkipSpace() {
+ s.skipSpace(false)
+}
+
// 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 io.RuneReader.
@@ -324,7 +335,6 @@ func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
return
}
-
var ssFree = newCache(func() interface{} { return new(ss) })
// Allocate a new ss struct or grab a cached one.
@@ -398,7 +408,6 @@ func (s *ss) skipSpace(stopAtNewline bool) {
}
}
-
// 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.
@@ -426,8 +435,8 @@ func (s *ss) typeError(field interface{}, expected string) {
s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String())
}
-var complexError = os.ErrorString("syntax error scanning complex number")
-var boolError = os.ErrorString("syntax error scanning boolean")
+var complexError = os.NewError("syntax error scanning complex number")
+var boolError = os.NewError("syntax error scanning boolean")
// consume reads the next rune in the input and reports whether it is in the ok string.
// If accept is true, it puts the character into the input token.
@@ -457,6 +466,14 @@ func (s *ss) peek(ok string) bool {
return strings.IndexRune(ok, rune) >= 0
}
+func (s *ss) notEOF() {
+ // Guarantee there is data to be read.
+ if rune := s.getRune(); rune == eof {
+ panic(os.EOF)
+ }
+ s.UnreadRune()
+}
+
// 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 {
@@ -476,11 +493,13 @@ func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
// scanBool returns the value of the boolean represented by the next token.
func (s *ss) scanBool(verb int) bool {
+ s.skipSpace(false)
+ s.notEOF()
if !s.okVerb(verb, "tv", "boolean") {
return false
}
// Syntax-checking a boolean is annoying. We're not fastidious about case.
- switch s.mustReadRune() {
+ switch s.getRune() {
case '0':
return false
case '1':
@@ -531,8 +550,11 @@ func (s *ss) getBase(verb int) (base int, digits string) {
// scanNumber returns the numerical string with specified digits starting here.
func (s *ss) scanNumber(digits string, haveDigits bool) string {
- if !haveDigits && !s.accept(digits) {
- s.errorString("expected integer")
+ if !haveDigits {
+ s.notEOF()
+ if !s.accept(digits) {
+ s.errorString("expected integer")
+ }
}
for s.accept(digits) {
}
@@ -541,7 +563,8 @@ func (s *ss) scanNumber(digits string, haveDigits bool) string {
// scanRune returns the next rune value in the input.
func (s *ss) scanRune(bitSize int) int64 {
- rune := int64(s.mustReadRune())
+ s.notEOF()
+ rune := int64(s.getRune())
n := uint(bitSize)
x := (rune << (64 - n)) >> (64 - n)
if x != rune {
@@ -575,6 +598,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 {
return s.scanRune(bitSize)
}
s.skipSpace(false)
+ s.notEOF()
base, digits := s.getBase(verb)
haveDigits := false
if verb == 'U' {
@@ -607,6 +631,7 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 {
return uint64(s.scanRune(bitSize))
}
s.skipSpace(false)
+ s.notEOF()
base, digits := s.getBase(verb)
haveDigits := false
if verb == 'U' {
@@ -727,6 +752,7 @@ func (s *ss) scanComplex(verb int, n int) complex128 {
return 0
}
s.skipSpace(false)
+ s.notEOF()
sreal, simag := s.complexTokens()
real := s.convertFloat(sreal, n/2)
imag := s.convertFloat(simag, n/2)
@@ -740,6 +766,7 @@ func (s *ss) convertString(verb int) (str string) {
return ""
}
s.skipSpace(false)
+ s.notEOF()
switch verb {
case 'q':
str = s.quotedString()
@@ -748,16 +775,13 @@ func (s *ss) convertString(verb int) (str string) {
default:
str = string(s.token(true, notSpace)) // %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.mustReadRune()
+ s.notEOF()
+ quote := s.getRune()
switch quote {
case '`':
// Back-quoted: Anything goes until EOF or back quote.
@@ -827,6 +851,7 @@ func (s *ss) hexByte() (b byte, ok bool) {
// hexString returns the space-delimited hexpair-encoded string.
func (s *ss) hexString() string {
+ s.notEOF()
for {
b, ok := s.hexByte()
if !ok {
@@ -860,6 +885,7 @@ func (s *ss) scanOne(verb int, field interface{}) {
}
return
}
+
switch v := field.(type) {
case *bool:
*v = s.scanBool(verb)
@@ -894,11 +920,13 @@ func (s *ss) scanOne(verb int, field interface{}) {
case *float32:
if s.okVerb(verb, floatVerbs, "float32") {
s.skipSpace(false)
+ s.notEOF()
*v = float32(s.convertFloat(s.floatToken(), 32))
}
case *float64:
if s.okVerb(verb, floatVerbs, "float64") {
s.skipSpace(false)
+ s.notEOF()
*v = s.convertFloat(s.floatToken(), 64)
}
case *string:
@@ -927,7 +955,7 @@ func (s *ss) scanOne(verb int, field interface{}) {
// For now, can only handle (renamed) []byte.
typ := v.Type()
if typ.Elem().Kind() != reflect.Uint8 {
- goto CantHandle
+ s.errorString("Scan: can't handle type: " + val.Type().String())
}
str := s.convertString(verb)
v.Set(reflect.MakeSlice(typ, len(str), len(str)))
@@ -936,23 +964,23 @@ func (s *ss) scanOne(verb int, field interface{}) {
}
case reflect.Float32, reflect.Float64:
s.skipSpace(false)
+ s.notEOF()
v.SetFloat(s.convertFloat(s.floatToken(), v.Type().Bits()))
case reflect.Complex64, reflect.Complex128:
v.SetComplex(s.scanComplex(verb, v.Type().Bits()))
default:
- CantHandle:
s.errorString("Scan: can't handle type: " + val.Type().String())
}
}
}
-// errorHandler turns local panics into error returns. EOFs are benign.
+// errorHandler turns local panics into error returns.
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
- }
+ *errp = se.err
+ } else if eof, ok := e.(os.Error); ok && eof == os.EOF { // out of input
+ *errp = eof
} else {
panic(e)
}
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
index da13eb2d112..3f06e5725ca 100644
--- a/libgo/go/fmt/scan_test.go
+++ b/libgo/go/fmt/scan_test.go
@@ -94,7 +94,7 @@ func (x *Xs) Scan(state ScanState, verb int) os.Error {
}
s := string(tok)
if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) {
- return os.ErrorString("syntax error for xs")
+ return os.NewError("syntax error for xs")
}
*x = Xs(s)
return nil
@@ -298,6 +298,8 @@ var scanfTests = []ScanfTest{
// Fixed bugs
{"%d\n", "27\n", &intVal, 27}, // ok
{"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
+ {"%v", "0", &intVal, 0}, // was: "EOF"; 0 was taken as base prefix and not counted.
+ {"%v", "0", &uintVal, uint(0)}, // was: "EOF"; 0 was taken as base prefix and not counted.
}
var overflowTests = []ScanTest{
@@ -660,6 +662,68 @@ func TestEOF(t *testing.T) {
}
}
+// Verify that we see an EOF error if we run out of input.
+// This was a buglet: we used to get "expected integer".
+func TestEOFAtEndOfInput(t *testing.T) {
+ var i, j int
+ n, err := Sscanf("23", "%d %d", &i, &j)
+ if n != 1 || i != 23 {
+ t.Errorf("Sscanf expected one value of 23; got %d %d", n, i)
+ }
+ if err != os.EOF {
+ t.Errorf("Sscanf expected EOF; got %q", err)
+ }
+ n, err = Sscan("234", &i, &j)
+ if n != 1 || i != 234 {
+ t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
+ }
+ if err != os.EOF {
+ t.Errorf("Sscan expected EOF; got %q", err)
+ }
+ // Trailing space is tougher.
+ n, err = Sscan("234 ", &i, &j)
+ if n != 1 || i != 234 {
+ t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
+ }
+ if err != os.EOF {
+ t.Errorf("Sscan expected EOF; got %q", err)
+ }
+}
+
+var eofTests = []struct {
+ format string
+ v interface{}
+}{
+ {"%s", &stringVal},
+ {"%q", &stringVal},
+ {"%x", &stringVal},
+ {"%v", &stringVal},
+ {"%v", &bytesVal},
+ {"%v", &intVal},
+ {"%v", &uintVal},
+ {"%v", &boolVal},
+ {"%v", &float32Val},
+ {"%v", &complex64Val},
+ {"%v", &renamedStringVal},
+ {"%v", &renamedBytesVal},
+ {"%v", &renamedIntVal},
+ {"%v", &renamedUintVal},
+ {"%v", &renamedBoolVal},
+ {"%v", &renamedFloat32Val},
+ {"%v", &renamedComplex64Val},
+}
+
+func TestEOFAllTypes(t *testing.T) {
+ for i, test := range eofTests {
+ if _, err := Sscanf("", test.format, test.v); err != os.EOF {
+ t.Errorf("#%d: %s %T not eof on empty string: %s", i, test.format, test.v, err)
+ }
+ if _, err := Sscanf(" ", test.format, test.v); err != os.EOF {
+ t.Errorf("#%d: %s %T not eof on trailing blanks: %s", i, test.format, test.v, err)
+ }
+ }
+}
+
// 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"))
@@ -756,7 +820,7 @@ func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) {
next := new(RecursiveInt)
_, err = Fscanf(state, ".%v", next)
if err != nil {
- if err == os.ErrorString("input does not match format") || err == io.ErrUnexpectedEOF {
+ if err == os.NewError("input does not match format") || err == io.ErrUnexpectedEOF {
err = nil
}
return
diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go
index 2fc1a60323d..22bd5ee2266 100644
--- a/libgo/go/go/ast/ast.go
+++ b/libgo/go/go/ast/ast.go
@@ -13,7 +13,6 @@ import (
"utf8"
)
-
// ----------------------------------------------------------------------------
// Interfaces
//
@@ -31,35 +30,30 @@ import (
// 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
@@ -69,11 +63,9 @@ type Comment struct {
Text string // 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.
//
@@ -81,11 +73,9 @@ 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
@@ -101,7 +91,6 @@ type Field struct {
Comment *CommentGroup // line comments; or nil
}
-
func (f *Field) Pos() token.Pos {
if len(f.Names) > 0 {
return f.Names[0].Pos()
@@ -109,7 +98,6 @@ func (f *Field) Pos() token.Pos {
return f.Type.Pos()
}
-
func (f *Field) End() token.Pos {
if f.Tag != nil {
return f.Tag.End()
@@ -117,15 +105,13 @@ func (f *Field) End() token.Pos {
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
+ List []*Field // field list; or nil
Closing token.Pos // position of closing parenthesis/brace, if any
}
-
func (f *FieldList) Pos() token.Pos {
if f.Opening.IsValid() {
return f.Opening
@@ -138,7 +124,6 @@ func (f *FieldList) Pos() token.Pos {
return token.NoPos
}
-
func (f *FieldList) End() token.Pos {
if f.Closing.IsValid() {
return f.Closing + 1
@@ -151,7 +136,6 @@ func (f *FieldList) End() token.Pos {
return token.NoPos
}
-
// NumFields returns the number of (named and anonymous fields) in a FieldList.
func (f *FieldList) NumFields() int {
n := 0
@@ -167,7 +151,6 @@ func (f *FieldList) NumFields() int {
return n
}
-
// An expression is represented by a tree consisting of one
// or more of the following concrete expression nodes.
//
@@ -298,7 +281,6 @@ type (
}
)
-
// The direction of a channel type is indicated by one
// of the following constants.
//
@@ -309,7 +291,6 @@ const (
RECV
)
-
// A type is represented by a tree consisting of one
// or more of the following type-specific expression
// nodes.
@@ -334,7 +315,7 @@ type (
// A FuncType node represents a function type.
FuncType struct {
Func token.Pos // position of "func" keyword
- Params *FieldList // (incoming) parameters
+ Params *FieldList // (incoming) parameters; or nil
Results *FieldList // (outgoing) results; or nil
}
@@ -360,7 +341,6 @@ type (
}
)
-
// Pos and End implementations for expression/type nodes.
//
func (x *BadExpr) Pos() token.Pos { return x.From }
@@ -391,7 +371,6 @@ 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 {
@@ -430,7 +409,6 @@ 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.
//
@@ -458,7 +436,6 @@ func (x *InterfaceType) exprNode() {}
func (x *MapType) exprNode() {}
func (x *ChanType) exprNode() {}
-
// ----------------------------------------------------------------------------
// Convenience functions for Idents
@@ -469,7 +446,6 @@ var noPos token.Pos
//
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).
//
@@ -478,13 +454,11 @@ func IsExported(name string) bool {
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
@@ -492,7 +466,6 @@ func (id *Ident) String() string {
return "<nil>"
}
-
// ----------------------------------------------------------------------------
// Statements
@@ -515,10 +488,10 @@ type (
// An EmptyStmt node represents an empty statement.
// The "position" of the empty statement is the position
- // of the immediately preceeding semicolon.
+ // of the immediately preceding semicolon.
//
EmptyStmt struct {
- Semicolon token.Pos // position of preceeding ";"
+ Semicolon token.Pos // position of preceding ";"
}
// A LabeledStmt node represents a labeled statement.
@@ -596,7 +569,7 @@ type (
// An IfStmt node represents an if statement.
IfStmt struct {
If token.Pos // position of "if" keyword
- Init Stmt // initalization statement; or nil
+ Init Stmt // initialization statement; or nil
Cond Expr // condition
Body *BlockStmt
Else Stmt // else branch; or nil
@@ -613,7 +586,7 @@ type (
// A SwitchStmt node represents an expression switch statement.
SwitchStmt struct {
Switch token.Pos // position of "switch" keyword
- Init Stmt // initalization statement; or nil
+ Init Stmt // initialization statement; or nil
Tag Expr // tag expression; or nil
Body *BlockStmt // CaseClauses only
}
@@ -621,7 +594,7 @@ type (
// An TypeSwitchStmt node represents a type switch statement.
TypeSwitchStmt struct {
Switch token.Pos // position of "switch" keyword
- Init Stmt // initalization statement; or nil
+ Init Stmt // initialization statement; or nil
Assign Stmt // x := y.(type) or y.(type)
Body *BlockStmt // CaseClauses only
}
@@ -643,7 +616,7 @@ type (
// A ForStmt represents a for statement.
ForStmt struct {
For token.Pos // position of "for" keyword
- Init Stmt // initalization statement; or nil
+ Init Stmt // initialization statement; or nil
Cond Expr // condition; or nil
Post Stmt // post iteration statement; or nil
Body *BlockStmt
@@ -660,7 +633,6 @@ type (
}
)
-
// Pos and End implementations for statement nodes.
//
func (s *BadStmt) Pos() token.Pos { return s.From }
@@ -685,7 +657,6 @@ 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 {
@@ -737,7 +708,6 @@ 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.
//
@@ -763,7 +733,6 @@ func (s *SelectStmt) stmtNode() {}
func (s *ForStmt) stmtNode() {}
func (s *RangeStmt) stmtNode() {}
-
// ----------------------------------------------------------------------------
// Declarations
@@ -805,7 +774,6 @@ type (
}
)
-
// Pos and End implementations for spec nodes.
//
func (s *ImportSpec) Pos() token.Pos {
@@ -817,7 +785,6 @@ func (s *ImportSpec) Pos() token.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 {
@@ -830,7 +797,6 @@ func (s *ValueSpec) End() token.Pos {
}
func (s *TypeSpec) End() token.Pos { return s.Type.End() }
-
// specNode() ensures that only spec nodes can be
// assigned to a Spec.
//
@@ -838,7 +804,6 @@ func (s *ImportSpec) specNode() {}
func (s *ValueSpec) specNode() {}
func (s *TypeSpec) specNode() {}
-
// A declaration is represented by one of the following declaration nodes.
//
type (
@@ -880,14 +845,12 @@ type (
}
)
-
// 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() {
@@ -902,7 +865,6 @@ func (d *FuncDecl) End() token.Pos {
return d.Type.End()
}
-
// declNode() ensures that only declaration nodes can be
// assigned to a DeclNode.
//
@@ -910,7 +872,6 @@ func (d *BadDecl) declNode() {}
func (d *GenDecl) declNode() {}
func (d *FuncDecl) declNode() {}
-
// ----------------------------------------------------------------------------
// Files and packages
@@ -931,7 +892,6 @@ type File struct {
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 {
@@ -940,17 +900,15 @@ func (f *File) End() token.Pos {
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
- Imports map[string]*Scope // map of import path -> package scope across all files
- Files map[string]*File // Go source files by filename
+ Name string // package name
+ Scope *Scope // package scope across all files
+ Imports map[string]*Object // map of package id -> package object
+ 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
index 090d08d34c7..26733430d64 100644
--- a/libgo/go/go/ast/filter.go
+++ b/libgo/go/go/ast/filter.go
@@ -20,25 +20,25 @@ func identListExports(list []*Ident) []*Ident {
return list[0:j]
}
-
-// isExportedType assumes that typ is a correct type.
-func isExportedType(typ Expr) bool {
- switch t := typ.(type) {
+// fieldName assumes that x is the type of an anonymous field and
+// returns the corresponding field name. If x is not an acceptable
+// anonymous field, the result is nil.
+//
+func fieldName(x Expr) *Ident {
+ switch t := x.(type) {
case *Ident:
- return t.IsExported()
- case *ParenExpr:
- return isExportedType(t.X)
+ return t
case *SelectorExpr:
- // assume t.X is a typename
- return t.Sel.IsExported()
+ if _, ok := t.X.(*Ident); ok {
+ return t.Sel
+ }
case *StarExpr:
- return isExportedType(t.X)
+ return fieldName(t.X)
}
- return false
+ return nil
}
-
-func fieldListExports(fields *FieldList, incomplete *bool) {
+func fieldListExports(fields *FieldList) (removedFields bool) {
if fields == nil {
return
}
@@ -53,12 +53,13 @@ func fieldListExports(fields *FieldList, incomplete *bool) {
// fields, so this is not absolutely correct.
// However, this cannot be done w/o complete
// type information.)
- exported = isExportedType(f.Type)
+ name := fieldName(f.Type)
+ exported = name != nil && name.IsExported()
} else {
n := len(f.Names)
f.Names = identListExports(f.Names)
if len(f.Names) < n {
- *incomplete = true
+ removedFields = true
}
exported = len(f.Names) > 0
}
@@ -69,12 +70,12 @@ func fieldListExports(fields *FieldList, incomplete *bool) {
}
}
if j < len(list) {
- *incomplete = true
+ removedFields = true
}
fields.List = list[0:j]
+ return
}
-
func paramListExports(fields *FieldList) {
if fields == nil {
return
@@ -84,18 +85,21 @@ func paramListExports(fields *FieldList) {
}
}
-
func typeExports(typ Expr) {
switch t := typ.(type) {
case *ArrayType:
typeExports(t.Elt)
case *StructType:
- fieldListExports(t.Fields, &t.Incomplete)
+ if fieldListExports(t.Fields) {
+ t.Incomplete = true
+ }
case *FuncType:
paramListExports(t.Params)
paramListExports(t.Results)
case *InterfaceType:
- fieldListExports(t.Methods, &t.Incomplete)
+ if fieldListExports(t.Methods) {
+ t.Incomplete = true
+ }
case *MapType:
typeExports(t.Key)
typeExports(t.Value)
@@ -104,7 +108,6 @@ func typeExports(typ Expr) {
}
}
-
func specExports(spec Spec) bool {
switch s := spec.(type) {
case *ValueSpec:
@@ -122,7 +125,6 @@ func specExports(spec Spec) bool {
return false
}
-
func specListExports(list []Spec) []Spec {
j := 0
for _, s := range list {
@@ -134,7 +136,6 @@ func specListExports(list []Spec) []Spec {
return list[0:j]
}
-
func declExports(decl Decl) bool {
switch d := decl.(type) {
case *GenDecl:
@@ -147,7 +148,6 @@ func declExports(decl Decl) bool {
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
@@ -170,7 +170,6 @@ func FileExports(src *File) bool {
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.
@@ -188,7 +187,6 @@ func PackageExports(pkg *Package) bool {
return hasExports
}
-
// ----------------------------------------------------------------------------
// General filtering
@@ -205,6 +203,37 @@ func filterIdentList(list []*Ident, f Filter) []*Ident {
return list[0:j]
}
+func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) {
+ if fields == nil {
+ return false
+ }
+ list := fields.List
+ j := 0
+ for _, f := range list {
+ keepField := false
+ if len(f.Names) == 0 {
+ // anonymous field
+ name := fieldName(f.Type)
+ keepField = name != nil && filter(name.Name)
+ } else {
+ n := len(f.Names)
+ f.Names = filterIdentList(f.Names, filter)
+ if len(f.Names) < n {
+ removedFields = true
+ }
+ keepField = len(f.Names) > 0
+ }
+ if keepField {
+ list[j] = f
+ j++
+ }
+ }
+ if j < len(list) {
+ removedFields = true
+ }
+ fields.List = list[0:j]
+ return
+}
func filterSpec(spec Spec, f Filter) bool {
switch s := spec.(type) {
@@ -212,12 +241,25 @@ func filterSpec(spec Spec, f Filter) bool {
s.Names = filterIdentList(s.Names, f)
return len(s.Names) > 0
case *TypeSpec:
- return f(s.Name.Name)
+ if f(s.Name.Name) {
+ return true
+ }
+ switch t := s.Type.(type) {
+ case *StructType:
+ if filterFieldList(t.Fields, f) {
+ t.Incomplete = true
+ }
+ return len(t.Fields.List) > 0
+ case *InterfaceType:
+ if filterFieldList(t.Methods, f) {
+ t.Incomplete = true
+ }
+ return len(t.Methods.List) > 0
+ }
}
return false
}
-
func filterSpecList(list []Spec, f Filter) []Spec {
j := 0
for _, s := range list {
@@ -229,8 +271,14 @@ func filterSpecList(list []Spec, f Filter) []Spec {
return list[0:j]
}
-
-func filterDecl(decl Decl, f Filter) bool {
+// FilterDecl trims the AST for a Go declaration in place by removing
+// all names (including struct field and interface method names, but
+// not from parameter lists) that don't pass through the filter f.
+//
+// FilterDecl returns true if there are any declared names left after
+// filtering; it returns false otherwise.
+//
+func FilterDecl(decl Decl, f Filter) bool {
switch d := decl.(type) {
case *GenDecl:
d.Specs = filterSpecList(d.Specs, f)
@@ -241,12 +289,11 @@ func filterDecl(decl Decl, f Filter) bool {
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.
+// names from top-level declarations (including struct field and
+// interface method names, but not from parameter lists) 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
@@ -255,7 +302,7 @@ func filterDecl(decl Decl, f Filter) bool {
func FilterFile(src *File, f Filter) bool {
j := 0
for _, d := range src.Decls {
- if filterDecl(d, f) {
+ if FilterDecl(d, f) {
src.Decls[j] = d
j++
}
@@ -264,12 +311,11 @@ func FilterFile(src *File, f Filter) bool {
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.
+// names from top-level declarations (including struct field and
+// interface method names, but not from parameter lists) 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.
//
@@ -286,7 +332,6 @@ func FilterPackage(pkg *Package, f Filter) bool {
return hasDecls
}
-
// ----------------------------------------------------------------------------
// Merging of package files
@@ -306,7 +351,6 @@ const (
//
var separator = &Comment{noPos, "//"}
-
// MergePackageFiles creates a file AST by merging the ASTs of the
// files belonging to a package. The mode flags control merging behavior.
//
diff --git a/libgo/go/go/ast/print.go b/libgo/go/go/ast/print.go
index 81e1da1d0aa..62a30481d5c 100644
--- a/libgo/go/go/ast/print.go
+++ b/libgo/go/go/ast/print.go
@@ -14,11 +14,9 @@ import (
"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, v reflect.Value) bool {
@@ -29,7 +27,6 @@ func NotNilFilter(_ string, v reflect.Value) bool {
return true
}
-
// Fprint prints the (sub-)tree starting at AST node x to w.
// If fset != nil, position information is interpreted relative
// to that file set. Otherwise positions are printed as integer
@@ -68,14 +65,12 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i
return
}
-
// Print prints x to standard output, skipping nil fields.
// Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
return Fprint(os.Stdout, fset, x, NotNilFilter)
}
-
type printer struct {
output io.Writer
fset *token.FileSet
@@ -87,7 +82,6 @@ type printer struct {
line int // current line number
}
-
var indent = []byte(". ")
func (p *printer) Write(data []byte) (n int, err os.Error) {
@@ -120,14 +114,12 @@ func (p *printer) Write(data []byte) (n int, err os.Error) {
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...)
@@ -137,7 +129,6 @@ func (p *printer) printf(format string, args ...interface{}) {
}
}
-
// 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.
diff --git a/libgo/go/go/ast/print_test.go b/libgo/go/go/ast/print_test.go
index 0820dcfcef2..f4e8f7a78f7 100644
--- a/libgo/go/go/ast/print_test.go
+++ b/libgo/go/go/ast/print_test.go
@@ -10,7 +10,6 @@ import (
"testing"
)
-
var tests = []struct {
x interface{} // x is printed as s
s string
@@ -49,11 +48,10 @@ var tests = []struct {
3 }`},
}
-
// Split s into lines, trim whitespace from all lines, and return
// the concatenated non-empty lines.
func trim(s string) string {
- lines := strings.Split(s, "\n", -1)
+ lines := strings.Split(s, "\n")
i := 0
for _, line := range lines {
line = strings.TrimSpace(line)
@@ -65,7 +63,6 @@ func trim(s string) string {
return strings.Join(lines[0:i], "\n")
}
-
func TestPrint(t *testing.T) {
var buf bytes.Buffer
for _, test := range tests {
diff --git a/libgo/go/go/ast/resolve.go b/libgo/go/go/ast/resolve.go
index fddc3baab86..3927a799e0a 100644
--- a/libgo/go/go/ast/resolve.go
+++ b/libgo/go/go/ast/resolve.go
@@ -11,25 +11,22 @@ import (
"go/scanner"
"go/token"
"os"
+ "strconv"
)
-
type pkgBuilder struct {
scanner.ErrorVector
fset *token.FileSet
}
-
func (p *pkgBuilder) error(pos token.Pos, msg string) {
p.Error(p.fset.Position(pos), msg)
}
-
func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) {
p.error(pos, fmt.Sprintf(format, args...))
}
-
func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) {
alt := scope.Insert(obj)
if alt == nil && altScope != nil {
@@ -45,7 +42,6 @@ func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) {
}
}
-
func resolve(scope *Scope, ident *Ident) bool {
for ; scope != nil; scope = scope.Outer {
if obj := scope.Lookup(ident.Name); obj != nil {
@@ -56,13 +52,16 @@ func resolve(scope *Scope, ident *Ident) bool {
return false
}
-
-// NewPackage uses an Importer to resolve imports. Given an importPath,
-// an importer returns the imported package's name, its scope of exported
-// objects, and an error, if any.
-//
-type Importer func(path string) (name string, scope *Scope, err os.Error)
-
+// An Importer resolves import paths to package Objects.
+// The imports map records the packages already imported,
+// indexed by package id (canonical import path).
+// An Importer must determine the canonical import path and
+// check the map to see if it is already present in the imports map.
+// If so, the Importer can return the map entry. Otherwise, the
+// Importer should load the package data for the given path into
+// a new *Object (pkg), record pkg in the imports map, and then
+// return pkg.
+type Importer func(imports map[string]*Object, path string) (pkg *Object, err os.Error)
// NewPackage creates a new Package node from a set of File nodes. It resolves
// unresolved identifiers across files and updates each file's Unresolved list
@@ -70,7 +69,7 @@ type Importer func(path string) (name string, scope *Scope, err os.Error)
// used to resolve identifiers not declared in any of the package files. Any
// remaining unresolved identifiers are reported as undeclared. If the files
// belong to different packages, one package name is selected and files with
-// different package name are reported and then ignored.
+// different package names are reported and then ignored.
// The result is a package node and a scanner.ErrorList if there were errors.
//
func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, os.Error) {
@@ -96,14 +95,8 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
}
}
- // imports maps import paths to package names and scopes
- // TODO(gri): Eventually we like to get to the import scope from
- // a package object. Then we can have a map path -> Obj.
- type importedPkg struct {
- name string
- scope *Scope
- }
- imports := make(map[string]*importedPkg)
+ // package global mapping of imported package ids to package objects
+ imports := make(map[string]*Object)
// complete file scopes with imports and resolve identifiers
for _, file := range files {
@@ -117,42 +110,41 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
importErrors := false
fileScope := NewScope(pkgScope)
for _, spec := range file.Imports {
- // add import to global map of imports
- path := string(spec.Path.Value)
- path = path[1 : len(path)-1] // strip ""'s
- pkg := imports[path]
- if pkg == nil {
- if importer == nil {
- importErrors = true
- continue
- }
- name, scope, err := importer(path)
- if err != nil {
- p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
- importErrors = true
- continue
- }
- pkg = &importedPkg{name, scope}
- imports[path] = pkg
- // TODO(gri) If a local package name != "." is provided,
- // global identifier resolution could proceed even if the
- // import failed. Consider adjusting the logic here a bit.
+ if importer == nil {
+ importErrors = true
+ continue
+ }
+ path, _ := strconv.Unquote(string(spec.Path.Value))
+ pkg, err := importer(imports, path)
+ if err != nil {
+ p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
+ importErrors = true
+ continue
}
+ // TODO(gri) If a local package name != "." is provided,
+ // global identifier resolution could proceed even if the
+ // import failed. Consider adjusting the logic here a bit.
+
// local name overrides imported package name
- name := pkg.name
+ name := pkg.Name
if spec.Name != nil {
name = spec.Name.Name
}
+
// add import to file scope
if name == "." {
// merge imported scope with file scope
- for _, obj := range pkg.scope.Objects {
+ for _, obj := range pkg.Data.(*Scope).Objects {
p.declare(fileScope, pkgScope, obj)
}
} else {
// declare imported package object in file scope
+ // (do not re-use pkg in the file scope but create
+ // a new object instead; the Decl field is different
+ // for different files)
obj := NewObj(Pkg, name)
obj.Decl = spec
+ obj.Data = pkg.Data
p.declare(fileScope, pkgScope, obj)
}
}
@@ -161,8 +153,8 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
if importErrors {
// don't use the universe scope without correct imports
// (objects in the universe may be shadowed by imports;
- // with missing imports identifiers might get resolved
- // wrongly)
+ // with missing imports, identifiers might get resolved
+ // incorrectly to universe objects)
pkgScope.Outer = nil
}
i := 0
@@ -178,11 +170,5 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer,
pkgScope.Outer = universe // reset universe scope
}
- // collect all import paths and respective package scopes
- importedScopes := make(map[string]*Scope)
- for path, pkg := range imports {
- importedScopes[path] = pkg.scope
- }
-
- return &Package{pkgName, pkgScope, importedScopes, files}, p.GetError(scanner.Sorted)
+ return &Package{pkgName, pkgScope, imports, files}, p.GetError(scanner.Sorted)
}
diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go
index 830d88aef4a..92e36698081 100644
--- a/libgo/go/go/ast/scope.go
+++ b/libgo/go/go/ast/scope.go
@@ -12,7 +12,6 @@ import (
"go/token"
)
-
// A Scope maintains the set of named language entities declared
// in the scope and a link to the immediately surrounding (outer)
// scope.
@@ -22,14 +21,12 @@ type Scope struct {
Objects map[string]*Object
}
-
// NewScope creates a new scope nested in the outer scope.
func NewScope(outer *Scope) *Scope {
const n = 4 // initial scope capacity
return &Scope{outer, make(map[string]*Object, n)}
}
-
// Lookup returns the object with the given name if it is
// found in scope s, otherwise it returns nil. Outer scopes
// are ignored.
@@ -38,7 +35,6 @@ func (s *Scope) Lookup(name string) *Object {
return s.Objects[name]
}
-
// Insert attempts to insert a named object obj into the scope s.
// If the scope already contains an object alt with the same name,
// Insert leaves the scope unchanged and returns alt. Otherwise
@@ -51,7 +47,6 @@ func (s *Scope) Insert(obj *Object) (alt *Object) {
return
}
-
// Debugging support
func (s *Scope) String() string {
var buf bytes.Buffer
@@ -66,27 +61,35 @@ func (s *Scope) String() string {
return buf.String()
}
-
// ----------------------------------------------------------------------------
// Objects
+// TODO(gri) Consider replacing the Object struct with an interface
+// and a corresponding set of object implementations.
+
// An Object describes a named language entity such as a package,
// constant, type, variable, function (incl. methods), or label.
//
+// The Data fields contains object-specific data:
+//
+// Kind Data type Data value
+// Pkg *Scope package scope
+// Con int iota for the respective declaration
+// Con != nil constant value
+//
type Object struct {
Kind ObjKind
Name string // declared name
Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+ Data interface{} // object-specific data; or nil
Type interface{} // place holder for type information; may be nil
}
-
// NewObj creates a new object of a given kind and name.
func NewObj(kind ObjKind, name string) *Object {
return &Object{Kind: kind, Name: name}
}
-
// Pos computes the source position of the declaration of an object name.
// The result may be an invalid position if it cannot be computed
// (obj.Decl may be nil or not correct).
@@ -126,7 +129,6 @@ func (obj *Object) Pos() token.Pos {
return token.NoPos
}
-
// ObKind describes what an object represents.
type ObjKind int
@@ -141,7 +143,6 @@ const (
Lbl // label
)
-
var objKindStrings = [...]string{
Bad: "bad",
Pkg: "package",
@@ -152,5 +153,4 @@ var objKindStrings = [...]string{
Lbl: "label",
}
-
func (kind ObjKind) String() string { return objKindStrings[kind] }
diff --git a/libgo/go/go/ast/walk.go b/libgo/go/go/ast/walk.go
index 95c4b3a3564..181cfd1491a 100644
--- a/libgo/go/go/ast/walk.go
+++ b/libgo/go/go/ast/walk.go
@@ -13,7 +13,6 @@ type Visitor interface {
Visit(node Node) (w Visitor)
}
-
// Helper functions for common node lists. They may be empty.
func walkIdentList(v Visitor, list []*Ident) {
@@ -22,28 +21,24 @@ func walkIdentList(v Visitor, list []*Ident) {
}
}
-
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).
@@ -369,7 +364,6 @@ func Walk(v Visitor, node Node) {
v.Visit(nil)
}
-
type inspector func(Node) bool
func (f inspector) Visit(node Node) Visitor {
@@ -379,7 +373,6 @@ func (f inspector) Visit(node Node) Visitor {
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.
diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go
new file mode 100644
index 00000000000..97f92bfb6e7
--- /dev/null
+++ b/libgo/go/go/build/build.go
@@ -0,0 +1,444 @@
+// 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 build provides tools for building Go packages.
+package build
+
+import (
+ "bytes"
+ "exec"
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+)
+
+// Build produces a build Script for the given package.
+func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
+ s := &Script{}
+ b := &build{
+ script: s,
+ path: filepath.Join(tree.SrcDir(), pkg),
+ }
+ b.obj = b.abs("_obj") + string(filepath.Separator)
+
+ b.goarch = runtime.GOARCH
+ if g := os.Getenv("GOARCH"); g != "" {
+ b.goarch = g
+ }
+ var err os.Error
+ b.arch, err = ArchChar(b.goarch)
+ if err != nil {
+ return nil, err
+ }
+
+ // add import object files to list of Inputs
+ for _, pkg := range info.Imports {
+ t, p, err := FindTree(pkg)
+ if err != nil && err != ErrNotFound {
+ // FindTree should always be able to suggest an import
+ // path and tree. The path must be malformed
+ // (for example, an absolute or relative path).
+ return nil, os.NewError("build: invalid import: " + pkg)
+ }
+ s.addInput(filepath.Join(t.PkgDir(), p+".a"))
+ }
+
+ // .go files to be built with gc
+ gofiles := b.abss(info.GoFiles...)
+ s.addInput(gofiles...)
+
+ var ofiles []string // object files to be linked or packed
+
+ // make build directory
+ b.mkdir(b.obj)
+ s.addIntermediate(b.obj)
+
+ // cgo
+ if len(info.CgoFiles) > 0 {
+ cgoFiles := b.abss(info.CgoFiles...)
+ s.addInput(cgoFiles...)
+ cgoCFiles := b.abss(info.CFiles...)
+ s.addInput(cgoCFiles...)
+ outGo, outObj := b.cgo(cgoFiles, cgoCFiles)
+ gofiles = append(gofiles, outGo...)
+ ofiles = append(ofiles, outObj...)
+ s.addIntermediate(outGo...)
+ s.addIntermediate(outObj...)
+ }
+
+ // compile
+ if len(gofiles) > 0 {
+ ofile := b.obj + "_go_." + b.arch
+ b.gc(ofile, gofiles...)
+ ofiles = append(ofiles, ofile)
+ s.addIntermediate(ofile)
+ }
+
+ // assemble
+ for _, sfile := range info.SFiles {
+ ofile := b.obj + sfile[:len(sfile)-1] + b.arch
+ sfile = b.abs(sfile)
+ s.addInput(sfile)
+ b.asm(ofile, sfile)
+ ofiles = append(ofiles, ofile)
+ s.addIntermediate(ofile)
+ }
+
+ if len(ofiles) == 0 {
+ return nil, os.NewError("make: no object files to build")
+ }
+
+ // choose target file
+ var targ string
+ if info.IsCommand() {
+ // use the last part of the import path as binary name
+ _, bin := filepath.Split(pkg)
+ if runtime.GOOS == "windows" {
+ bin += ".exe"
+ }
+ targ = filepath.Join(tree.BinDir(), bin)
+ } else {
+ targ = filepath.Join(tree.PkgDir(), pkg+".a")
+ }
+
+ // make target directory
+ targDir, _ := filepath.Split(targ)
+ b.mkdir(targDir)
+
+ // link binary or pack object
+ if info.IsCommand() {
+ b.ld(targ, ofiles...)
+ } else {
+ b.gopack(targ, ofiles...)
+ }
+ s.Output = append(s.Output, targ)
+
+ return b.script, nil
+}
+
+// A Script describes the build process for a Go package.
+// The Input, Intermediate, and Output fields are lists of absolute paths.
+type Script struct {
+ Cmd []*Cmd
+ Input []string
+ Intermediate []string
+ Output []string
+}
+
+func (s *Script) addInput(file ...string) {
+ s.Input = append(s.Input, file...)
+}
+
+func (s *Script) addIntermediate(file ...string) {
+ s.Intermediate = append(s.Intermediate, file...)
+}
+
+// Run runs the Script's Cmds in order.
+func (s *Script) Run() os.Error {
+ for _, c := range s.Cmd {
+ if err := c.Run(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Stale returns true if the build's inputs are newer than its outputs.
+func (s *Script) Stale() bool {
+ var latest int64
+ // get latest mtime of outputs
+ for _, file := range s.Output {
+ fi, err := os.Stat(file)
+ if err != nil {
+ // any error reading output files means stale
+ return true
+ }
+ if m := fi.Mtime_ns; m > latest {
+ latest = m
+ }
+ }
+ for _, file := range s.Input {
+ fi, err := os.Stat(file)
+ if err != nil || fi.Mtime_ns > latest {
+ // any error reading input files means stale
+ // (attempt to rebuild to figure out why)
+ return true
+ }
+ }
+ return false
+}
+
+// Clean removes the Script's Intermediate files.
+// It tries to remove every file and returns the first error it encounters.
+func (s *Script) Clean() (err os.Error) {
+ // Reverse order so that directories get removed after the files they contain.
+ for i := len(s.Intermediate) - 1; i >= 0; i-- {
+ if e := os.Remove(s.Intermediate[i]); err == nil {
+ err = e
+ }
+ }
+ return
+}
+
+// Nuke removes the Script's Intermediate and Output files.
+// It tries to remove every file and returns the first error it encounters.
+func (s *Script) Nuke() (err os.Error) {
+ // Reverse order so that directories get removed after the files they contain.
+ for i := len(s.Output) - 1; i >= 0; i-- {
+ if e := os.Remove(s.Output[i]); err == nil {
+ err = e
+ }
+ }
+ if e := s.Clean(); err == nil {
+ err = e
+ }
+ return
+}
+
+// A Cmd describes an individual build command.
+type Cmd struct {
+ Args []string // command-line
+ Stdout string // write standard output to this file, "" is passthrough
+ Dir string // working directory
+ Env []string // environment
+ Input []string // file paths (dependencies)
+ Output []string // file paths
+}
+
+func (c *Cmd) String() string {
+ return strings.Join(c.Args, " ")
+}
+
+// Run executes the Cmd.
+func (c *Cmd) Run() os.Error {
+ if c.Args[0] == "mkdir" {
+ for _, p := range c.Output {
+ if err := os.MkdirAll(p, 0777); err != nil {
+ return fmt.Errorf("command %q: %v", c, err)
+ }
+ }
+ return nil
+ }
+ out := new(bytes.Buffer)
+ cmd := exec.Command(c.Args[0], c.Args[1:]...)
+ cmd.Dir = c.Dir
+ cmd.Env = c.Env
+ cmd.Stdout = out
+ cmd.Stderr = out
+ if c.Stdout != "" {
+ f, err := os.Create(c.Stdout)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ cmd.Stdout = f
+ }
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("command %q: %v\n%v", c, err, out)
+ }
+ return nil
+}
+
+// ArchChar returns the architecture character for the given goarch.
+// For example, ArchChar("amd64") returns "6".
+func ArchChar(goarch string) (string, os.Error) {
+ switch goarch {
+ case "386":
+ return "8", nil
+ case "amd64":
+ return "6", nil
+ case "arm":
+ return "5", nil
+ }
+ return "", os.NewError("unsupported GOARCH " + goarch)
+}
+
+type build struct {
+ script *Script
+ path string
+ obj string
+ goarch string
+ arch string
+}
+
+func (b *build) abs(file string) string {
+ if filepath.IsAbs(file) {
+ return file
+ }
+ return filepath.Join(b.path, file)
+}
+
+func (b *build) abss(file ...string) []string {
+ s := make([]string, len(file))
+ for i, f := range file {
+ s[i] = b.abs(f)
+ }
+ return s
+}
+
+func (b *build) add(c Cmd) {
+ b.script.Cmd = append(b.script.Cmd, &c)
+}
+
+func (b *build) mkdir(name string) {
+ b.add(Cmd{
+ Args: []string{"mkdir", "-p", name},
+ Output: []string{name},
+ })
+}
+
+func (b *build) gc(ofile string, gofiles ...string) {
+ gc := b.arch + "g"
+ args := append([]string{gc, "-o", ofile}, gcImportArgs...)
+ args = append(args, gofiles...)
+ b.add(Cmd{
+ Args: args,
+ Input: gofiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) asm(ofile string, sfile string) {
+ asm := b.arch + "a"
+ b.add(Cmd{
+ Args: []string{asm, "-o", ofile, sfile},
+ Input: []string{sfile},
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) ld(targ string, ofiles ...string) {
+ ld := b.arch + "l"
+ args := append([]string{ld, "-o", targ}, ldImportArgs...)
+ args = append(args, ofiles...)
+ b.add(Cmd{
+ Args: args,
+ Input: ofiles,
+ Output: []string{targ},
+ })
+}
+
+func (b *build) gopack(targ string, ofiles ...string) {
+ b.add(Cmd{
+ Args: append([]string{"gopack", "grc", targ}, ofiles...),
+ Input: ofiles,
+ Output: []string{targ},
+ })
+}
+
+func (b *build) cc(ofile string, cfiles ...string) {
+ cc := b.arch + "c"
+ dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
+ inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
+ args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
+ b.add(Cmd{
+ Args: append(args, cfiles...),
+ Input: cfiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccCompile(ofile, cfile string) {
+ b.add(Cmd{
+ Args: b.gccArgs("-o", ofile, "-c", cfile),
+ Input: []string{cfile},
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccLink(ofile string, ofiles ...string) {
+ b.add(Cmd{
+ Args: append(b.gccArgs("-o", ofile), ofiles...),
+ Input: ofiles,
+ Output: []string{ofile},
+ })
+}
+
+func (b *build) gccArgs(args ...string) []string {
+ // TODO(adg): HOST_CC
+ a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
+ switch b.arch {
+ case "8":
+ a = append(a, "-m32")
+ case "6":
+ a = append(a, "-m64")
+ }
+ return append(a, args...)
+}
+
+var cgoRe = regexp.MustCompile(`[/\\:]`)
+
+func (b *build) cgo(cgofiles, cgocfiles []string) (outGo, outObj []string) {
+ // cgo
+ // TODO(adg): CGOPKGPATH
+ // TODO(adg): CGO_FLAGS
+ gofiles := []string{b.obj + "_cgo_gotypes.go"}
+ cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
+ for _, fn := range cgofiles {
+ f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
+ gofiles = append(gofiles, f+"cgo1.go")
+ cfiles = append(cfiles, f+"cgo2.c")
+ }
+ defunC := b.obj + "_cgo_defun.c"
+ output := append([]string{defunC}, cfiles...)
+ output = append(output, gofiles...)
+ b.add(Cmd{
+ Args: append([]string{"cgo", "--"}, cgofiles...),
+ Dir: b.path,
+ Env: append(os.Environ(), "GOARCH="+b.goarch),
+ Input: cgofiles,
+ Output: output,
+ })
+ outGo = append(outGo, gofiles...)
+ exportH := filepath.Join(b.path, "_cgo_export.h")
+ b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags")
+ b.script.addIntermediate(cfiles...)
+
+ // cc _cgo_defun.c
+ defunObj := b.obj + "_cgo_defun." + b.arch
+ b.cc(defunObj, defunC)
+ outObj = append(outObj, defunObj)
+
+ // gcc
+ linkobj := make([]string, 0, len(cfiles))
+ for _, cfile := range cfiles {
+ ofile := cfile[:len(cfile)-1] + "o"
+ b.gccCompile(ofile, cfile)
+ linkobj = append(linkobj, ofile)
+ if !strings.HasSuffix(ofile, "_cgo_main.o") {
+ outObj = append(outObj, ofile)
+ } else {
+ b.script.addIntermediate(ofile)
+ }
+ }
+ for _, cfile := range cgocfiles {
+ ofile := b.obj + cgoRe.ReplaceAllString(cfile[:len(cfile)-1], "_") + "o"
+ b.gccCompile(ofile, cfile)
+ linkobj = append(linkobj, ofile)
+ outObj = append(outObj, ofile)
+ }
+ dynObj := b.obj + "_cgo_.o"
+ b.gccLink(dynObj, linkobj...)
+ b.script.addIntermediate(dynObj)
+
+ // cgo -dynimport
+ importC := b.obj + "_cgo_import.c"
+ b.add(Cmd{
+ Args: []string{"cgo", "-dynimport", dynObj},
+ Stdout: importC,
+ Input: []string{dynObj},
+ Output: []string{importC},
+ })
+ b.script.addIntermediate(importC)
+
+ // cc _cgo_import.ARCH
+ importObj := b.obj + "_cgo_import." + b.arch
+ b.cc(importObj, importC)
+ outObj = append(outObj, importObj)
+
+ return
+}
diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go
new file mode 100644
index 00000000000..e59d87672ca
--- /dev/null
+++ b/libgo/go/go/build/build_test.go
@@ -0,0 +1,61 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package build
+
+import (
+ "exec"
+ "path/filepath"
+ "testing"
+)
+
+var buildPkgs = []string{
+ "go/build/pkgtest",
+ "go/build/cmdtest",
+ "go/build/cgotest",
+}
+
+const cmdtestOutput = "3"
+
+func TestBuild(t *testing.T) {
+ for _, pkg := range buildPkgs {
+ tree := Path[0] // Goroot
+ dir := filepath.Join(tree.SrcDir(), pkg)
+
+ info, err := ScanDir(dir, true)
+ if err != nil {
+ t.Error("ScanDir:", err)
+ continue
+ }
+
+ s, err := Build(tree, pkg, info)
+ if err != nil {
+ t.Error("Build:", err)
+ continue
+ }
+
+ if err := s.Run(); err != nil {
+ t.Error("Run:", err)
+ continue
+ }
+
+ if pkg == "go/build/cmdtest" {
+ bin := s.Output[0]
+ b, err := exec.Command(bin).CombinedOutput()
+ if err != nil {
+ t.Errorf("exec: %s: %v", bin, err)
+ continue
+ }
+ if string(b) != cmdtestOutput {
+ t.Errorf("cmdtest output: %s want: %s", b, cmdtestOutput)
+ }
+ }
+
+ defer func(s *Script) {
+ if err := s.Nuke(); err != nil {
+ t.Errorf("nuking: %v", err)
+ }
+ }(s)
+ }
+}
diff --git a/libgo/go/go/build/cgotest/cgotest.go b/libgo/go/go/build/cgotest/cgotest.go
new file mode 100644
index 00000000000..93bbf06883f
--- /dev/null
+++ b/libgo/go/go/build/cgotest/cgotest.go
@@ -0,0 +1,19 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+char* greeting = "hello, world";
+*/
+// #include "cgotest.h"
+import "C"
+import "unsafe"
+
+var Greeting = C.GoString(C.greeting)
+
+func DoAdd(x, y int) (sum int) {
+ C.Add(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&sum)))
+ return
+}
diff --git a/libgo/go/go/build/cmdtest/main.go b/libgo/go/go/build/cmdtest/main.go
new file mode 100644
index 00000000000..bed4f485a0a
--- /dev/null
+++ b/libgo/go/go/build/cmdtest/main.go
@@ -0,0 +1,12 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "go/build/pkgtest"
+
+func main() {
+ pkgtest.Foo()
+ print(int(pkgtest.Sqrt(9)))
+}
diff --git a/libgo/go/go/build/dir.go b/libgo/go/go/build/dir.go
new file mode 100644
index 00000000000..e0000b53446
--- /dev/null
+++ b/libgo/go/go/build/dir.go
@@ -0,0 +1,172 @@
+// 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 build
+
+import (
+ "go/parser"
+ "go/token"
+ "log"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "runtime"
+)
+
+type DirInfo struct {
+ GoFiles []string // .go files in dir (excluding CgoFiles)
+ CgoFiles []string // .go files that import "C"
+ CFiles []string // .c files in dir
+ SFiles []string // .s files in dir
+ Imports []string // All packages imported by goFiles
+ PkgName string // Name of package in dir
+}
+
+func (d *DirInfo) IsCommand() bool {
+ return d.PkgName == "main"
+}
+
+// ScanDir returns a structure with details about the Go content found
+// in the given directory. The file lists exclude:
+//
+// - files in package main (unless allowMain is true)
+// - files in package documentation
+// - files ending in _test.go
+// - files starting with _ or .
+//
+// Only files that satisfy the goodOSArch function are included.
+func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) {
+ f, err := os.Open(dir)
+ if err != nil {
+ return nil, err
+ }
+ dirs, err := f.Readdir(-1)
+ f.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ var di DirInfo
+ imported := make(map[string]bool)
+ fset := token.NewFileSet()
+ for i := range dirs {
+ d := &dirs[i]
+ if strings.HasPrefix(d.Name, "_") ||
+ strings.HasPrefix(d.Name, ".") {
+ continue
+ }
+ if !goodOSArch(d.Name) {
+ continue
+ }
+
+ switch filepath.Ext(d.Name) {
+ case ".go":
+ if strings.HasSuffix(d.Name, "_test.go") {
+ continue
+ }
+ case ".c":
+ di.CFiles = append(di.CFiles, d.Name)
+ continue
+ case ".s":
+ di.SFiles = append(di.SFiles, d.Name)
+ continue
+ default:
+ continue
+ }
+
+ filename := filepath.Join(dir, d.Name)
+ pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
+ if err != nil {
+ return nil, err
+ }
+ s := string(pf.Name.Name)
+ if s == "main" && !allowMain {
+ continue
+ }
+ if s == "documentation" {
+ continue
+ }
+ if di.PkgName == "" {
+ di.PkgName = s
+ } else if di.PkgName != s {
+ // Only if all files in the directory are in package main
+ // do we return PkgName=="main".
+ // A mix of main and another package reverts
+ // to the original (allowMain=false) behaviour.
+ if s == "main" || di.PkgName == "main" {
+ return ScanDir(dir, false)
+ }
+ return nil, os.NewError("multiple package names in " + dir)
+ }
+ isCgo := false
+ for _, spec := range pf.Imports {
+ quoted := string(spec.Path.Value)
+ path, err := strconv.Unquote(quoted)
+ if err != nil {
+ log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ }
+ imported[path] = true
+ if path == "C" {
+ isCgo = true
+ }
+ }
+ if isCgo {
+ di.CgoFiles = append(di.CgoFiles, d.Name)
+ } else {
+ di.GoFiles = append(di.GoFiles, d.Name)
+ }
+ }
+ di.Imports = make([]string, len(imported))
+ i := 0
+ for p := range imported {
+ di.Imports[i] = p
+ i++
+ }
+ return &di, nil
+}
+
+// goodOSArch returns false if the filename contains a $GOOS or $GOARCH
+// suffix which does not match the current system.
+// The recognized filename formats are:
+//
+// name_$(GOOS).*
+// name_$(GOARCH).*
+// name_$(GOOS)_$(GOARCH).*
+//
+func goodOSArch(filename string) bool {
+ if dot := strings.Index(filename, "."); dot != -1 {
+ filename = filename[:dot]
+ }
+ l := strings.Split(filename, "_")
+ n := len(l)
+ if n == 0 {
+ return true
+ }
+ if good, known := goodOS[l[n-1]]; known {
+ return good
+ }
+ if good, known := goodArch[l[n-1]]; known {
+ if !good || n < 2 {
+ return false
+ }
+ good, known = goodOS[l[n-2]]
+ return good || !known
+ }
+ return true
+}
+
+var goodOS = make(map[string]bool)
+var goodArch = make(map[string]bool)
+
+func init() {
+ goodOS = make(map[string]bool)
+ goodArch = make(map[string]bool)
+ for _, v := range strings.Fields(goosList) {
+ goodOS[v] = v == runtime.GOOS
+ }
+ for _, v := range strings.Fields(goarchList) {
+ goodArch[v] = v == runtime.GOARCH
+ }
+}
diff --git a/libgo/go/go/build/path.go b/libgo/go/go/build/path.go
new file mode 100644
index 00000000000..e39b5f8fa57
--- /dev/null
+++ b/libgo/go/go/build/path.go
@@ -0,0 +1,182 @@
+// 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 build
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+)
+
+// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init.
+var Path []*Tree
+
+// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
+type Tree struct {
+ Path string
+ Goroot bool
+}
+
+func newTree(p string) (*Tree, os.Error) {
+ if !filepath.IsAbs(p) {
+ return nil, os.NewError("must be absolute")
+ }
+ ep, err := filepath.EvalSymlinks(p)
+ if err != nil {
+ return nil, err
+ }
+ return &Tree{Path: ep}, nil
+}
+
+// SrcDir returns the tree's package source directory.
+func (t *Tree) SrcDir() string {
+ if t.Goroot {
+ return filepath.Join(t.Path, "src", "pkg")
+ }
+ return filepath.Join(t.Path, "src")
+}
+
+// PkgDir returns the tree's package object directory.
+func (t *Tree) PkgDir() string {
+ goos, goarch := runtime.GOOS, runtime.GOARCH
+ if e := os.Getenv("GOOS"); e != "" {
+ goos = e
+ }
+ if e := os.Getenv("GOARCH"); e != "" {
+ goarch = e
+ }
+ return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
+}
+
+// BinDir returns the tree's binary executable directory.
+func (t *Tree) BinDir() string {
+ if t.Goroot {
+ if gobin := os.Getenv("GOBIN"); gobin != "" {
+ return gobin
+ }
+ }
+ return filepath.Join(t.Path, "bin")
+}
+
+// HasSrc returns whether the given package's
+// source can be found inside this Tree.
+func (t *Tree) HasSrc(pkg string) bool {
+ fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
+ if err != nil {
+ return false
+ }
+ return fi.IsDirectory()
+}
+
+// HasPkg returns whether the given package's
+// object file can be found inside this Tree.
+func (t *Tree) HasPkg(pkg string) bool {
+ fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
+ if err != nil {
+ return false
+ }
+ return fi.IsRegular()
+ // TODO(adg): check object version is consistent
+}
+
+var (
+ ErrNotFound = os.NewError("go/build: package could not be found locally")
+ ErrTreeNotFound = os.NewError("go/build: no valid GOROOT or GOPATH could be found")
+)
+
+// FindTree takes an import or filesystem path and returns the
+// tree where the package source should be and the package import path.
+func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
+ if isLocalPath(path) {
+ if path, err = filepath.Abs(path); err != nil {
+ return
+ }
+ if path, err = filepath.EvalSymlinks(path); err != nil {
+ return
+ }
+ for _, t := range Path {
+ tpath := t.SrcDir() + string(filepath.Separator)
+ if !filepath.HasPrefix(path, tpath) {
+ continue
+ }
+ tree = t
+ pkg = path[len(tpath):]
+ return
+ }
+ err = fmt.Errorf("path %q not inside a GOPATH", path)
+ return
+ }
+ tree = defaultTree
+ pkg = path
+ for _, t := range Path {
+ if t.HasSrc(pkg) {
+ tree = t
+ return
+ }
+ }
+ if tree == nil {
+ err = ErrTreeNotFound
+ } else {
+ err = ErrNotFound
+ }
+ return
+}
+
+// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
+// Windows paths that starts with drive letter (c:\foo c:foo) are considered local.
+func isLocalPath(s string) bool {
+ const sep = string(filepath.Separator)
+ return s == "." || s == ".." ||
+ filepath.HasPrefix(s, sep) ||
+ filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) ||
+ filepath.VolumeName(s) != ""
+}
+
+var (
+ // argument lists used by the build's gc and ld methods
+ gcImportArgs []string
+ ldImportArgs []string
+
+ // default tree for remote packages
+ defaultTree *Tree
+)
+
+// set up Path: parse and validate GOROOT and GOPATH variables
+func init() {
+ root := runtime.GOROOT()
+ t, err := newTree(root)
+ if err != nil {
+ log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+ } else {
+ t.Goroot = true
+ Path = []*Tree{t}
+ }
+
+ for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
+ if p == "" {
+ continue
+ }
+ t, err := newTree(p)
+ if err != nil {
+ log.Printf("go/build: invalid GOPATH %q: %v", p, err)
+ continue
+ }
+ Path = append(Path, t)
+ gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
+ ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())
+
+ // select first GOPATH entry as default
+ if defaultTree == nil {
+ defaultTree = t
+ }
+ }
+
+ // use GOROOT if no valid GOPATH specified
+ if defaultTree == nil && len(Path) > 0 {
+ defaultTree = Path[0]
+ }
+}
diff --git a/libgo/go/go/build/pkgtest/pkgtest.go b/libgo/go/go/build/pkgtest/pkgtest.go
new file mode 100644
index 00000000000..9322f5ebd71
--- /dev/null
+++ b/libgo/go/go/build/pkgtest/pkgtest.go
@@ -0,0 +1,9 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkgtest
+
+func Foo() {}
+
+func Sqrt(x float64) float64
diff --git a/libgo/go/go/build/syslist_test.go b/libgo/go/go/build/syslist_test.go
new file mode 100644
index 00000000000..eb0e5dcb6b2
--- /dev/null
+++ b/libgo/go/go/build/syslist_test.go
@@ -0,0 +1,62 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package build
+
+import (
+ "runtime"
+ "testing"
+)
+
+var (
+ thisOS = runtime.GOOS
+ thisArch = runtime.GOARCH
+ otherOS = anotherOS()
+ otherArch = anotherArch()
+)
+
+func anotherOS() string {
+ if thisOS != "darwin" {
+ return "darwin"
+ }
+ return "linux"
+}
+
+func anotherArch() string {
+ if thisArch != "amd64" {
+ return "amd64"
+ }
+ return "386"
+}
+
+type GoodFileTest struct {
+ name string
+ result bool
+}
+
+var tests = []GoodFileTest{
+ {"file.go", true},
+ {"file.c", true},
+ {"file_foo.go", true},
+ {"file_" + thisArch + ".go", true},
+ {"file_" + otherArch + ".go", false},
+ {"file_" + thisOS + ".go", true},
+ {"file_" + otherOS + ".go", false},
+ {"file_" + thisOS + "_" + thisArch + ".go", true},
+ {"file_" + otherOS + "_" + thisArch + ".go", false},
+ {"file_" + thisOS + "_" + otherArch + ".go", false},
+ {"file_" + otherOS + "_" + otherArch + ".go", false},
+ {"file_foo_" + thisArch + ".go", true},
+ {"file_foo_" + otherArch + ".go", false},
+ {"file_" + thisOS + ".c", true},
+ {"file_" + otherOS + ".c", false},
+}
+
+func TestGoodOSArch(t *testing.T) {
+ for _, test := range tests {
+ if goodOSArch(test.name) != test.result {
+ t.Fatalf("goodOSArch(%q) != %v", test.name, test.result)
+ }
+ }
+}
diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go
index f1ebfa97b9f..e1989226b68 100644
--- a/libgo/go/go/doc/comment.go
+++ b/libgo/go/go/doc/comment.go
@@ -11,13 +11,11 @@ import (
"io"
"regexp"
"strings"
- "template" // for htmlEscape
+ "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]) {
@@ -26,7 +24,6 @@ func stripTrailingWhitespace(s string) string {
return s[0:i]
}
-
// CommentText returns the text of comment,
// with the comment markers - //, /*, and */ - removed.
func CommentText(comment *ast.CommentGroup) string {
@@ -58,7 +55,7 @@ func CommentText(comment *ast.CommentGroup) string {
}
// Split on newlines.
- cl := strings.Split(c, "\n", -1)
+ cl := strings.Split(c, "\n")
// Walk lines, stripping trailing white space and adding to list.
for _, l := range cl {
@@ -85,7 +82,6 @@ func CommentText(comment *ast.CommentGroup) string {
return strings.Join(lines, "\n")
}
-
// Split bytes into lines.
func split(text []byte) [][]byte {
// count lines
@@ -119,7 +115,6 @@ func split(text []byte) [][]byte {
return out
}
-
var (
ldquo = []byte("&ldquo;")
rdquo = []byte("&rdquo;")
@@ -148,7 +143,6 @@ func commentEscape(w io.Writer, s []byte, nice bool) {
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
@@ -176,7 +170,6 @@ var (
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
@@ -235,7 +228,6 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
commentEscape(w, line, nice)
}
-
func indentLen(s []byte) int {
i := 0
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
@@ -244,10 +236,8 @@ func indentLen(s []byte) int {
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] {
@@ -256,7 +246,6 @@ func commonPrefix(a, b []byte) []byte {
return a[0:i]
}
-
func unindent(block [][]byte) {
if len(block) == 0 {
return
@@ -279,7 +268,6 @@ func unindent(block [][]byte) {
}
}
-
// Convert comment text to formatted HTML.
// The comment was prepared by DocReader,
// so it is known not to have leading, trailing blank lines
diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go
index 29d205d391c..c7fed97841c 100644
--- a/libgo/go/go/doc/doc.go
+++ b/libgo/go/go/doc/doc.go
@@ -12,7 +12,6 @@ import (
"sort"
)
-
// ----------------------------------------------------------------------------
type typeDoc struct {
@@ -25,7 +24,6 @@ type typeDoc struct {
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
@@ -42,14 +40,12 @@ type docReader struct {
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
@@ -71,7 +67,6 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
doc.doc = &ast.CommentGroup{list}
}
-
func (doc *docReader) addType(decl *ast.GenDecl) {
spec := decl.Specs[0].(*ast.TypeSpec)
typ := doc.lookupTypeDoc(spec.Name.Name)
@@ -84,7 +79,6 @@ func (doc *docReader) addType(decl *ast.GenDecl) {
}
}
-
func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
if name == "" {
return nil // no type docs for anonymous types
@@ -98,7 +92,6 @@ func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
return tdoc
}
-
func baseTypeName(typ ast.Expr) string {
switch t := typ.(type) {
case *ast.Ident:
@@ -113,7 +106,6 @@ func baseTypeName(typ ast.Expr) string {
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.
@@ -165,7 +157,6 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
*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.
@@ -183,7 +174,6 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
table[name] = f
}
-
func (doc *docReader) addFunc(fun *ast.FuncDecl) {
name := fun.Name.Name
@@ -238,7 +228,6 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
setFunc(doc.funcs, fun)
}
-
func (doc *docReader) addDecl(decl ast.Decl) {
switch d := decl.(type) {
case *ast.GenDecl:
@@ -271,7 +260,6 @@ func (doc *docReader) addDecl(decl ast.Decl) {
}
}
-
func copyCommentList(list []*ast.Comment) []*ast.Comment {
return append([]*ast.Comment(nil), list...)
}
@@ -281,7 +269,6 @@ var (
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.
//
@@ -313,7 +300,6 @@ func (doc *docReader) addFile(src *ast.File) {
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)
@@ -321,7 +307,6 @@ func NewFileDoc(file *ast.File) *PackageDoc {
return r.newDoc("", nil)
}
-
func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
var r docReader
r.init(pkg.Name)
@@ -335,7 +320,6 @@ func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
return r.newDoc(importpath, filenames)
}
-
// ----------------------------------------------------------------------------
// Conversion to external representation
@@ -353,7 +337,6 @@ 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 ""
@@ -369,7 +352,6 @@ func declName(d *ast.GenDecl) string {
return ""
}
-
func (p sortValueDoc) Less(i, j int) bool {
// sort by name
// pull blocks (name = "") up to top
@@ -380,7 +362,6 @@ func (p sortValueDoc) Less(i, j int) bool {
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
@@ -396,7 +377,6 @@ func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
return d
}
-
// FuncDoc is the documentation for a func declaration,
// either a top-level function or a method function.
//
@@ -413,7 +393,6 @@ 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
@@ -433,7 +412,6 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
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.
@@ -463,7 +441,6 @@ func (p sortTypeDoc) Less(i, j int) bool {
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.
@@ -520,7 +497,6 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
return d
}
-
func makeBugDocs(list []*ast.CommentGroup) []string {
d := make([]string, len(list))
for i, g := range list {
@@ -529,7 +505,6 @@ func makeBugDocs(list []*ast.CommentGroup) []string {
return d
}
-
// PackageDoc is the documentation for an entire package.
//
type PackageDoc struct {
@@ -544,14 +519,13 @@ type PackageDoc struct {
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)
+ sort.Strings(filenames)
p.Filenames = filenames
p.Doc = CommentText(doc.doc)
// makeTypeDocs may extend the list of doc.values and
@@ -565,12 +539,23 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
return p
}
-
// ----------------------------------------------------------------------------
// Filtering by name
type Filter func(string) bool
+func matchFields(fields *ast.FieldList, f Filter) bool {
+ if fields != nil {
+ for _, field := range fields.List {
+ for _, name := range field.Names {
+ if f(name.Name) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
func matchDecl(d *ast.GenDecl, f Filter) bool {
for _, d := range d.Specs {
@@ -585,12 +570,21 @@ func matchDecl(d *ast.GenDecl, f Filter) bool {
if f(v.Name.Name) {
return true
}
+ switch t := v.Type.(type) {
+ case *ast.StructType:
+ if matchFields(t.Fields, f) {
+ return true
+ }
+ case *ast.InterfaceType:
+ if matchFields(t.Methods, f) {
+ return true
+ }
+ }
}
}
return false
}
-
func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
w := 0
for _, vd := range a {
@@ -602,7 +596,6 @@ func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
return a[0:w]
}
-
func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
w := 0
for _, fd := range a {
@@ -614,7 +607,6 @@ func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
return a[0:w]
}
-
func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
w := 0
for _, td := range a {
@@ -637,7 +629,6 @@ func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
return a[0:w]
}
-
// Filter eliminates documentation for names that don't pass through the filter f.
// TODO: Recognize "Type.Method" as a name.
//
diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go
index b4780e05784..4f980fc6539 100644
--- a/libgo/go/go/parser/interface.go
+++ b/libgo/go/go/parser/interface.go
@@ -17,7 +17,6 @@ import (
"path/filepath"
)
-
// 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.
@@ -42,20 +41,21 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) {
}
return buf.Bytes(), nil
default:
- return nil, os.ErrorString("invalid source")
+ return nil, os.NewError("invalid source")
}
}
return ioutil.ReadFile(filename)
}
-
-func (p *parser) parseEOF() os.Error {
- p.expect(token.EOF)
- return p.GetError(scanner.Sorted)
+func (p *parser) errors() os.Error {
+ mode := scanner.Sorted
+ if p.mode&SpuriousErrors == 0 {
+ mode = scanner.NoMultiples
+ }
+ return p.GetError(mode)
}
-
// 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
@@ -73,9 +73,10 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr,
if p.tok == token.SEMICOLON {
p.next() // consume automatically inserted semicolon, if any
}
- return x, p.parseEOF()
-}
+ p.expect(token.EOF)
+ return x, p.errors()
+}
// ParseStmtList parses a list of Go statements and returns the list
// of corresponding AST nodes. The fset, filename, and src arguments have the same
@@ -90,9 +91,11 @@ func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast
var p parser
p.init(fset, filename, data, 0)
- return p.parseStmtList(), p.parseEOF()
-}
+ list := p.parseStmtList()
+ p.expect(token.EOF)
+ return list, p.errors()
+}
// ParseDeclList parses a list of Go declarations and returns the list
// of corresponding AST nodes. The fset, filename, and src arguments have the same
@@ -107,9 +110,11 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast
var p parser
p.init(fset, filename, data, 0)
- return p.parseDeclList(), p.parseEOF()
-}
+ list := p.parseDeclList()
+ p.expect(token.EOF)
+ return list, p.errors()
+}
// 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
@@ -139,9 +144,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint)
var p parser
p.init(fset, filename, data, mode)
- return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
-}
+ file := p.parseFile() // parseFile reads to EOF
+ return file, p.errors()
+}
// 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
@@ -171,7 +177,6 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st
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
diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go
index afa9ae517b6..9c14d166732 100644
--- a/libgo/go/go/parser/parser.go
+++ b/libgo/go/go/parser/parser.go
@@ -16,7 +16,6 @@ import (
"go/token"
)
-
// 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.
@@ -27,9 +26,9 @@ const (
ParseComments // parse comments and add them to AST
Trace // print a trace of parsed productions
DeclarationErrors // report declaration errors
+ SpuriousErrors // report all (not just the first) errors per line
)
-
// The parser structure holds the parser's internal state.
type parser struct {
file *token.File
@@ -54,7 +53,7 @@ type parser struct {
// Non-syntactic parser control
exprLev int // < 0: in control clause, >= 0: in expression
- // Ordinary identifer scopes
+ // Ordinary identifier scopes
pkgScope *ast.Scope // pkgScope.Outer == nil
topScope *ast.Scope // top-most scope; may be pkgScope
unresolved []*ast.Ident // unresolved identifiers
@@ -66,7 +65,6 @@ type parser struct {
targetStack [][]*ast.Ident // stack of unresolved labels
}
-
// scannerMode returns the scanner mode bits given the parser's mode bits.
func scannerMode(mode uint) uint {
var m uint = scanner.InsertSemis
@@ -76,7 +74,6 @@ func scannerMode(mode uint) uint {
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))
@@ -95,7 +92,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin
p.openLabelScope()
}
-
// ----------------------------------------------------------------------------
// Scoping support
@@ -103,18 +99,15 @@ func (p *parser) openScope() {
p.topScope = ast.NewScope(p.topScope)
}
-
func (p *parser) closeScope() {
p.topScope = p.topScope.Outer
}
-
func (p *parser) openLabelScope() {
p.labelScope = ast.NewScope(p.labelScope)
p.targetStack = append(p.targetStack, nil)
}
-
func (p *parser) closeLabelScope() {
// resolve labels
n := len(p.targetStack) - 1
@@ -130,15 +123,16 @@ func (p *parser) closeLabelScope() {
p.labelScope = p.labelScope.Outer
}
-
-func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
+func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
for _, ident := range idents {
assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(kind, ident.Name)
+ // remember the corresponding declaration for redeclaration
+ // errors and global variable resolution/typechecking phase
+ obj.Decl = decl
+ obj.Data = data
+ ident.Obj = obj
if ident.Name != "_" {
- obj := ast.NewObj(kind, ident.Name)
- // remember the corresponding declaration for redeclaration
- // errors and global variable resolution/typechecking phase
- obj.Decl = decl
if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 {
prevDecl := ""
if pos := alt.Pos(); pos.IsValid() {
@@ -146,12 +140,10 @@ func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, i
}
p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
}
- ident.Obj = obj
}
}
}
-
func (p *parser) shortVarDecl(idents []*ast.Ident) {
// Go spec: A short variable declaration may redeclare variables
// provided they were originally declared in the same block with
@@ -159,17 +151,17 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
n := 0 // number of new variables
for _, ident := range idents {
assert(ident.Obj == nil, "identifier already declared or resolved")
+ obj := ast.NewObj(ast.Var, ident.Name)
+ // short var declarations cannot have redeclaration errors
+ // and are not global => no need to remember the respective
+ // declaration
+ ident.Obj = obj
if ident.Name != "_" {
- obj := ast.NewObj(ast.Var, ident.Name)
- // short var declarations cannot have redeclaration errors
- // and are not global => no need to remember the respective
- // declaration
- alt := p.topScope.Insert(obj)
- if alt == nil {
+ if alt := p.topScope.Insert(obj); alt != nil {
+ ident.Obj = alt // redeclaration
+ } else {
n++ // new declaration
- alt = obj
}
- ident.Obj = alt
}
}
if n == 0 && p.mode&DeclarationErrors != 0 {
@@ -177,13 +169,11 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
}
}
-
// The unresolved object is a sentinel to mark identifiers that have been added
// to the list of unresolved identifiers. The sentinel is only used for verifying
// internal consistency.
var unresolved = new(ast.Object)
-
func (p *parser) resolve(x ast.Expr) {
// nothing to do if x is not an identifier or the blank identifier
ident, _ := x.(*ast.Ident)
@@ -209,7 +199,6 @@ func (p *parser) resolve(x ast.Expr) {
p.unresolved = append(p.unresolved, ident)
}
-
// ----------------------------------------------------------------------------
// Parsing support
@@ -227,21 +216,18 @@ func (p *parser) printTrace(a ...interface{}) {
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
@@ -283,7 +269,6 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
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
@@ -305,7 +290,6 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
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.
@@ -356,12 +340,10 @@ func (p *parser) next() {
}
}
-
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 {
@@ -379,7 +361,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
p.error(pos, msg)
}
-
func (p *parser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
@@ -389,21 +370,18 @@ func (p *parser) expect(tok token.Token) token.Pos {
return pos
}
-
func (p *parser) expectSemi() {
if p.tok != token.RPAREN && p.tok != token.RBRACE {
p.expect(token.SEMICOLON)
}
}
-
func assert(cond bool, msg string) {
if !cond {
panic("go/parser internal error: " + msg)
}
}
-
// ----------------------------------------------------------------------------
// Identifiers
@@ -419,7 +397,6 @@ func (p *parser) parseIdent() *ast.Ident {
return &ast.Ident{pos, name, nil}
}
-
func (p *parser) parseIdentList() (list []*ast.Ident) {
if p.trace {
defer un(trace(p, "IdentList"))
@@ -434,7 +411,6 @@ func (p *parser) parseIdentList() (list []*ast.Ident) {
return
}
-
// ----------------------------------------------------------------------------
// Common productions
@@ -444,16 +420,15 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
defer un(trace(p, "ExpressionList"))
}
- list = append(list, p.parseExpr(lhs))
+ list = append(list, p.checkExpr(p.parseExpr(lhs)))
for p.tok == token.COMMA {
p.next()
- list = append(list, p.parseExpr(lhs))
+ list = append(list, p.checkExpr(p.parseExpr(lhs)))
}
return
}
-
func (p *parser) parseLhsList() []ast.Expr {
list := p.parseExprList(true)
switch p.tok {
@@ -477,12 +452,10 @@ func (p *parser) parseLhsList() []ast.Expr {
return list
}
-
func (p *parser) parseRhsList() []ast.Expr {
return p.parseExprList(false)
}
-
// ----------------------------------------------------------------------------
// Types
@@ -503,7 +476,6 @@ func (p *parser) parseType() ast.Expr {
return typ
}
-
// If the result is an identifier, it is not resolved.
func (p *parser) parseTypeName() ast.Expr {
if p.trace {
@@ -524,7 +496,6 @@ func (p *parser) parseTypeName() ast.Expr {
return ident
}
-
func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "ArrayType"))
@@ -544,7 +515,6 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
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 {
@@ -559,7 +529,6 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
return idents
}
-
func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "FieldDecl"))
@@ -596,12 +565,11 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
p.expectSemi() // call before accessing p.linecomment
field := &ast.Field{doc, idents, typ, tag, p.lineComment}
- p.declare(field, scope, ast.Var, idents...)
+ p.declare(field, nil, scope, ast.Var, idents...)
return field
}
-
func (p *parser) parseStructType() *ast.StructType {
if p.trace {
defer un(trace(p, "StructType"))
@@ -623,7 +591,6 @@ func (p *parser) parseStructType() *ast.StructType {
return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
-
func (p *parser) parsePointerType() *ast.StarExpr {
if p.trace {
defer un(trace(p, "PointerType"))
@@ -635,7 +602,6 @@ func (p *parser) parsePointerType() *ast.StarExpr {
return &ast.StarExpr{star, base}
}
-
func (p *parser) tryVarType(isParam bool) ast.Expr {
if isParam && p.tok == token.ELLIPSIS {
pos := p.pos
@@ -653,7 +619,6 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
return p.tryIdentOrType(false)
}
-
func (p *parser) parseVarType(isParam bool) ast.Expr {
typ := p.tryVarType(isParam)
if typ == nil {
@@ -665,7 +630,6 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
return typ
}
-
func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
if p.trace {
defer un(trace(p, "VarList"))
@@ -693,7 +657,6 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
return
}
-
func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
if p.trace {
defer un(trace(p, "ParameterList"))
@@ -707,7 +670,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
params = append(params, field)
// Go spec: The scope of an identifier denoting a function
// parameter or result variable is the function body.
- p.declare(field, scope, ast.Var, idents...)
+ p.declare(field, nil, scope, ast.Var, idents...)
if p.tok == token.COMMA {
p.next()
}
@@ -719,7 +682,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
params = append(params, field)
// Go spec: The scope of an identifier denoting a function
// parameter or result variable is the function body.
- p.declare(field, scope, ast.Var, idents...)
+ p.declare(field, nil, scope, ast.Var, idents...)
if p.tok != token.COMMA {
break
}
@@ -738,7 +701,6 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
return
}
-
func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
if p.trace {
defer un(trace(p, "Parameters"))
@@ -754,7 +716,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
return &ast.FieldList{lparen, params, rparen}
}
-
func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
if p.trace {
defer un(trace(p, "Result"))
@@ -774,7 +735,6 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
return nil
}
-
func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
if p.trace {
defer un(trace(p, "Signature"))
@@ -786,7 +746,6 @@ func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldLis
return
}
-
func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
if p.trace {
defer un(trace(p, "FuncType"))
@@ -799,7 +758,6 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
return &ast.FuncType{pos, params, results}, scope
}
-
func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "MethodSpec"))
@@ -818,16 +776,16 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
} else {
// embedded interface
typ = x
+ p.resolve(typ)
}
p.expectSemi() // call before accessing p.linecomment
spec := &ast.Field{doc, idents, typ, nil, p.lineComment}
- p.declare(spec, scope, ast.Fun, idents...)
+ p.declare(spec, nil, scope, ast.Fun, idents...)
return spec
}
-
func (p *parser) parseInterfaceType() *ast.InterfaceType {
if p.trace {
defer un(trace(p, "InterfaceType"))
@@ -846,7 +804,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
-
func (p *parser) parseMapType() *ast.MapType {
if p.trace {
defer un(trace(p, "MapType"))
@@ -861,7 +818,6 @@ func (p *parser) parseMapType() *ast.MapType {
return &ast.MapType{pos, key, value}
}
-
func (p *parser) parseChanType() *ast.ChanType {
if p.trace {
defer un(trace(p, "ChanType"))
@@ -885,7 +841,6 @@ func (p *parser) parseChanType() *ast.ChanType {
return &ast.ChanType{pos, dir, value}
}
-
// If the result is an identifier, it is not resolved.
func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
switch p.tok {
@@ -918,7 +873,6 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
return nil
}
-
func (p *parser) tryType() ast.Expr {
typ := p.tryIdentOrType(false)
if typ != nil {
@@ -927,7 +881,6 @@ func (p *parser) tryType() ast.Expr {
return typ
}
-
// ----------------------------------------------------------------------------
// Blocks
@@ -943,7 +896,6 @@ func (p *parser) parseStmtList() (list []ast.Stmt) {
return
}
-
func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
if p.trace {
defer un(trace(p, "Body"))
@@ -960,7 +912,6 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
return &ast.BlockStmt{lbrace, list, rbrace}
}
-
func (p *parser) parseBlockStmt() *ast.BlockStmt {
if p.trace {
defer un(trace(p, "BlockStmt"))
@@ -975,7 +926,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
return &ast.BlockStmt{lbrace, list, rbrace}
}
-
// ----------------------------------------------------------------------------
// Expressions
@@ -997,7 +947,6 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
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.
// If lhs is set and the result is an identifier, it is not resolved.
@@ -1024,7 +973,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
lparen := p.pos
p.next()
p.exprLev++
- x := p.parseRhs()
+ x := p.parseRhsOrType() // types may be parenthesized: (some type)
p.exprLev--
rparen := p.expect(token.RPAREN)
return &ast.ParenExpr{lparen, x, rparen}
@@ -1047,7 +996,6 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
return &ast.BadExpr{pos, p.pos}
}
-
func (p *parser) parseSelector(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "Selector"))
@@ -1058,7 +1006,6 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr {
return &ast.SelectorExpr{x, sel}
}
-
func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "TypeAssertion"))
@@ -1077,7 +1024,6 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
return &ast.TypeAssertExpr{x, typ}
}
-
func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "IndexOrSlice"))
@@ -1106,7 +1052,6 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
return &ast.IndexExpr{x, lbrack, low, rbrack}
}
-
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
if p.trace {
defer un(trace(p, "CallOrConversion"))
@@ -1117,7 +1062,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
var list []ast.Expr
var ellipsis token.Pos
for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
- list = append(list, p.parseRhs())
+ list = append(list, p.parseRhsOrType()) // builtins may expect a type: make(some type, ...)
if p.tok == token.ELLIPSIS {
ellipsis = p.pos
p.next()
@@ -1133,7 +1078,6 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
}
-
func (p *parser) parseElement(keyOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "Element"))
@@ -1143,7 +1087,7 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
return p.parseLiteralValue(nil)
}
- x := p.parseExpr(keyOk) // don't resolve if map key
+ x := p.checkExpr(p.parseExpr(keyOk)) // don't resolve if map key
if keyOk {
if p.tok == token.COLON {
colon := p.pos
@@ -1156,7 +1100,6 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
return x
}
-
func (p *parser) parseElementList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "ElementList"))
@@ -1173,7 +1116,6 @@ func (p *parser) parseElementList() (list []ast.Expr) {
return
}
-
func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "LiteralValue"))
@@ -1190,7 +1132,6 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
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) {
@@ -1205,19 +1146,14 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
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()}
- }
+ // If t.Type == nil we have a type assertion of the form
+ // y.(type), which is only allowed in type switch expressions.
+ // It's hard to exclude those but for the case where we are in
+ // a type switch. Instead be lenient and test this in the type
+ // checker.
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
@@ -1227,7 +1163,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
return x
}
-
// isTypeName returns true iff x is a (qualified) TypeName.
func isTypeName(x ast.Expr) bool {
switch t := x.(type) {
@@ -1242,7 +1177,6 @@ func isTypeName(x ast.Expr) bool {
return true
}
-
// isLiteralType returns true iff x is a legal composite literal type.
func isLiteralType(x ast.Expr) bool {
switch t := x.(type) {
@@ -1260,7 +1194,6 @@ func isLiteralType(x ast.Expr) bool {
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 {
@@ -1269,7 +1202,6 @@ func deref(x ast.Expr) ast.Expr {
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 {
@@ -1278,7 +1210,6 @@ func unparen(x ast.Expr) ast.Expr {
return x
}
-
// checkExprOrType checks that x is an expression or a type
// (and not a raw type such as [...]T).
//
@@ -1287,11 +1218,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
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 '...'")
@@ -1303,7 +1229,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
if p.trace {
@@ -1358,7 +1283,6 @@ L:
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
if p.trace {
@@ -1366,7 +1290,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
}
switch p.tok {
- case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE:
+ case token.ADD, token.SUB, token.NOT, token.XOR, token.AND:
pos, op := p.pos, p.tok
p.next()
x := p.parseUnaryExpr(false)
@@ -1396,7 +1320,6 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
return p.parsePrimaryExpr(lhs)
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
if p.trace {
@@ -1420,10 +1343,10 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
-// TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
-// should reject when a type/raw type is obviously not allowed
+// The result may be a type or even a raw type ([...]int). Callers must
+// check the result (using checkExpr or checkExprOrType), depending on
+// context.
func (p *parser) parseExpr(lhs bool) ast.Expr {
if p.trace {
defer un(trace(p, "Expression"))
@@ -1432,16 +1355,29 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
return p.parseBinaryExpr(lhs, token.LowestPrec+1)
}
-
func (p *parser) parseRhs() ast.Expr {
- return p.parseExpr(false)
+ return p.checkExpr(p.parseExpr(false))
}
+func (p *parser) parseRhsOrType() ast.Expr {
+ return p.checkExprOrType(p.parseExpr(false))
+}
// ----------------------------------------------------------------------------
// Statements
-func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
+// Parsing modes for parseSimpleStmt.
+const (
+ basic = iota
+ labelOk
+ rangeOk
+)
+
+// parseSimpleStmt returns true as 2nd result if it parsed the assignment
+// of a range clause (with mode == rangeOk). The returned statement is an
+// assignment with a right-hand side that is a single unary expression of
+// the form "range x". No guarantees are given for the left-hand side.
+func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
if p.trace {
defer un(trace(p, "SimpleStmt"))
}
@@ -1454,11 +1390,20 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
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
+ // assignment statement, possibly part of a range clause
pos, tok := p.pos, p.tok
p.next()
- y := p.parseRhsList()
- return &ast.AssignStmt{x, pos, tok, y}
+ var y []ast.Expr
+ isRange := false
+ if mode == rangeOk && p.tok == token.RANGE && (tok == token.DEFINE || tok == token.ASSIGN) {
+ pos := p.pos
+ p.next()
+ y = []ast.Expr{&ast.UnaryExpr{pos, token.RANGE, p.parseRhs()}}
+ isRange = true
+ } else {
+ y = p.parseRhsList()
+ }
+ return &ast.AssignStmt{x, pos, tok, y}, isRange
}
if len(x) > 1 {
@@ -1471,38 +1416,43 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
// labeled statement
colon := p.pos
p.next()
- if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent {
+ if label, isIdent := x[0].(*ast.Ident); mode == labelOk && isIdent {
// Go spec: The scope of a label is the body of the function
// in which it is declared and excludes the body of any nested
// function.
stmt := &ast.LabeledStmt{label, colon, p.parseStmt()}
- p.declare(stmt, p.labelScope, ast.Lbl, label)
- return stmt
+ p.declare(stmt, nil, p.labelScope, ast.Lbl, label)
+ return stmt, false
}
- p.error(x[0].Pos(), "illegal label declaration")
- return &ast.BadStmt{x[0].Pos(), colon + 1}
+ // The label declaration typically starts at x[0].Pos(), but the label
+ // declaration may be erroneous due to a token after that position (and
+ // before the ':'). If SpuriousErrors is not set, the (only) error re-
+ // ported for the line is the illegal label error instead of the token
+ // before the ':' that caused the problem. Thus, use the (latest) colon
+ // position for error reporting.
+ p.error(colon, "illegal label declaration")
+ return &ast.BadStmt{x[0].Pos(), colon + 1}, false
case token.ARROW:
// send statement
arrow := p.pos
p.next() // consume "<-"
y := p.parseRhs()
- return &ast.SendStmt{x[0], arrow, y}
+ return &ast.SendStmt{x[0], arrow, y}, false
case token.INC, token.DEC:
// increment or decrement
s := &ast.IncDecStmt{x[0], p.pos, p.tok}
p.next() // consume "++" or "--"
- return s
+ return s, false
}
// expression
- return &ast.ExprStmt{x[0]}
+ return &ast.ExprStmt{x[0]}, false
}
-
func (p *parser) parseCallExpr() *ast.CallExpr {
- x := p.parseRhs()
+ x := p.parseRhsOrType() // could be a conversion: (some type)(x)
if call, isCall := x.(*ast.CallExpr); isCall {
return call
}
@@ -1510,7 +1460,6 @@ func (p *parser) parseCallExpr() *ast.CallExpr {
return nil
}
-
func (p *parser) parseGoStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "GoStmt"))
@@ -1526,7 +1475,6 @@ func (p *parser) parseGoStmt() ast.Stmt {
return &ast.GoStmt{pos, call}
}
-
func (p *parser) parseDeferStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "DeferStmt"))
@@ -1542,7 +1490,6 @@ func (p *parser) parseDeferStmt() ast.Stmt {
return &ast.DeferStmt{pos, call}
}
-
func (p *parser) parseReturnStmt() *ast.ReturnStmt {
if p.trace {
defer un(trace(p, "ReturnStmt"))
@@ -1559,7 +1506,6 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
return &ast.ReturnStmt{pos, x}
}
-
func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
if p.trace {
defer un(trace(p, "BranchStmt"))
@@ -1578,7 +1524,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
return &ast.BranchStmt{pos, tok, label}
}
-
func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
if s == nil {
return nil
@@ -1590,7 +1535,6 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
return &ast.BadExpr{s.Pos(), s.End()}
}
-
func (p *parser) parseIfStmt() *ast.IfStmt {
if p.trace {
defer un(trace(p, "IfStmt"))
@@ -1609,7 +1553,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p.next()
x = p.parseRhs()
} else {
- s = p.parseSimpleStmt(false)
+ s, _ = p.parseSimpleStmt(basic)
if p.tok == token.SEMICOLON {
p.next()
x = p.parseRhs()
@@ -1633,7 +1577,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
return &ast.IfStmt{pos, s, x, body, else_}
}
-
func (p *parser) parseTypeList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "TypeList"))
@@ -1648,7 +1591,6 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
return
}
-
func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
if p.trace {
defer un(trace(p, "CaseClause"))
@@ -1675,7 +1617,6 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
return &ast.CaseClause{pos, list, colon, body}
}
-
func isExprSwitch(s ast.Stmt) bool {
if s == nil {
return true
@@ -1689,7 +1630,6 @@ func isExprSwitch(s ast.Stmt) bool {
return false
}
-
func (p *parser) parseSwitchStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "SwitchStmt"))
@@ -1704,14 +1644,14 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
prevLev := p.exprLev
p.exprLev = -1
if p.tok != token.SEMICOLON {
- s2 = p.parseSimpleStmt(false)
+ s2, _ = p.parseSimpleStmt(basic)
}
if p.tok == token.SEMICOLON {
p.next()
s1 = s2
s2 = nil
if p.tok != token.LBRACE {
- s2 = p.parseSimpleStmt(false)
+ s2, _ = p.parseSimpleStmt(basic)
}
}
p.exprLev = prevLev
@@ -1735,7 +1675,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
return &ast.TypeSwitchStmt{pos, s1, s2, body}
}
-
func (p *parser) parseCommClause() *ast.CommClause {
if p.trace {
defer un(trace(p, "CommClause"))
@@ -1797,7 +1736,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
return &ast.CommClause{pos, comm, colon, body}
}
-
func (p *parser) parseSelectStmt() *ast.SelectStmt {
if p.trace {
defer un(trace(p, "SelectStmt"))
@@ -1816,7 +1754,6 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
return &ast.SelectStmt{pos, body}
}
-
func (p *parser) parseForStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "ForStmt"))
@@ -1827,22 +1764,23 @@ func (p *parser) parseForStmt() ast.Stmt {
defer p.closeScope()
var s1, s2, s3 ast.Stmt
+ var isRange bool
if p.tok != token.LBRACE {
prevLev := p.exprLev
p.exprLev = -1
if p.tok != token.SEMICOLON {
- s2 = p.parseSimpleStmt(false)
+ s2, isRange = p.parseSimpleStmt(rangeOk)
}
- if p.tok == token.SEMICOLON {
+ if !isRange && p.tok == token.SEMICOLON {
p.next()
s1 = s2
s2 = nil
if p.tok != token.SEMICOLON {
- s2 = p.parseSimpleStmt(false)
+ s2, _ = p.parseSimpleStmt(basic)
}
p.expectSemi()
if p.tok != token.LBRACE {
- s3 = p.parseSimpleStmt(false)
+ s3, _ = p.parseSimpleStmt(basic)
}
}
p.exprLev = prevLev
@@ -1851,12 +1789,8 @@ func (p *parser) parseForStmt() ast.Stmt {
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()}
- }
+ if isRange {
+ as := s2.(*ast.AssignStmt)
// check lhs
var key, value ast.Expr
switch len(as.Lhs) {
@@ -1868,25 +1802,16 @@ func (p *parser) parseForStmt() ast.Stmt {
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 expression")
- return &ast.BadStmt{pos, body.End()}
- }
- if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
- // rhs is range expression
- // (any short variable declaration was handled by parseSimpleStat above)
- return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
- }
- p.errorExpected(s2.Pos(), "range clause")
- return &ast.BadStmt{pos, body.End()}
+ // parseSimpleStmt returned a right-hand side that
+ // is a single unary expression of the form "range x"
+ x := as.Rhs[0].(*ast.UnaryExpr).X
+ return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, x, body}
}
// regular for statement
return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
}
-
func (p *parser) parseStmt() (s ast.Stmt) {
if p.trace {
defer un(trace(p, "Statement"))
@@ -1900,7 +1825,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
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)
+ s, _ = p.parseSimpleStmt(labelOk)
// because of the required look-ahead, labeled statements are
// parsed by parseSimpleStmt - don't expect a semicolon after
// them
@@ -1943,13 +1868,11 @@ func (p *parser) parseStmt() (s ast.Stmt) {
return
}
-
// ----------------------------------------------------------------------------
// Declarations
type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
-
func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "ImportSpec"))
@@ -1980,7 +1903,6 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
if p.trace {
defer un(trace(p, "ConstSpec"))
@@ -2000,12 +1922,11 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
// the end of the innermost containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
- p.declare(spec, p.topScope, ast.Con, idents...)
+ p.declare(spec, iota, p.topScope, ast.Con, idents...)
return spec
}
-
func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "TypeSpec"))
@@ -2018,7 +1939,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
// containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.TypeSpec{doc, ident, nil, nil}
- p.declare(spec, p.topScope, ast.Typ, ident)
+ p.declare(spec, nil, p.topScope, ast.Typ, ident)
spec.Type = p.parseType()
p.expectSemi() // call before accessing p.linecomment
@@ -2027,7 +1948,6 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "VarSpec"))
@@ -2047,12 +1967,11 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
// the end of the innermost containing block.
// (Global identifiers are resolved in a separate phase after parsing.)
spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
- p.declare(spec, p.topScope, ast.Var, idents...)
+ p.declare(spec, nil, p.topScope, ast.Var, idents...)
return spec
}
-
func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
if p.trace {
defer un(trace(p, "GenDecl("+keyword.String()+")"))
@@ -2077,7 +1996,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
}
-
func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
if p.trace {
defer un(trace(p, "Receiver"))
@@ -2105,7 +2023,6 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
return par
}
-
func (p *parser) parseFuncDecl() *ast.FuncDecl {
if p.trace {
defer un(trace(p, "FunctionDecl"))
@@ -2139,14 +2056,13 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
// init() functions cannot be referred to and there may
// be more than one - don't put them in the pkgScope
if ident.Name != "init" {
- p.declare(decl, p.pkgScope, ast.Fun, ident)
+ p.declare(decl, nil, p.pkgScope, ast.Fun, ident)
}
}
return decl
}
-
func (p *parser) parseDecl() ast.Decl {
if p.trace {
defer un(trace(p, "Declaration"))
@@ -2177,7 +2093,6 @@ func (p *parser) parseDecl() ast.Decl {
return p.parseGenDecl(p.tok, f)
}
-
func (p *parser) parseDeclList() (list []ast.Decl) {
if p.trace {
defer un(trace(p, "DeclList"))
@@ -2190,7 +2105,6 @@ func (p *parser) parseDeclList() (list []ast.Decl) {
return
}
-
// ----------------------------------------------------------------------------
// Source files
@@ -2243,6 +2157,5 @@ func (p *parser) parseFile() *ast.File {
}
}
- // TODO(gri): store p.imports in AST
return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments}
}
diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go
index 5b52f51d4a5..39a78e5156e 100644
--- a/libgo/go/go/parser/parser_test.go
+++ b/libgo/go/go/parser/parser_test.go
@@ -10,7 +10,6 @@ import (
"testing"
)
-
var fset = token.NewFileSet()
var illegalInputs = []interface{}{
@@ -22,9 +21,26 @@ var illegalInputs = []interface{}{
`package p; func f() { if ; /* should have condition */ {} };`,
`package p; func f() { if f(); /* should have condition */ {} };`,
`package p; const c; /* should have constant value */`,
+ `package p; func f() { if _ = range x; true {} };`,
+ `package p; func f() { switch _ = range x; true {} };`,
+ `package p; func f() { for _ = range x ; ; {} };`,
+ `package p; func f() { for ; ; _ = range x {} };`,
+ `package p; func f() { for ; _ = range x ; {} };`,
+ `package p; var a = [1]int; /* illegal expression */`,
+ `package p; var a = [...]int; /* illegal expression */`,
+ `package p; var a = struct{} /* illegal expression */`,
+ `package p; var a = func(); /* illegal expression */`,
+ `package p; var a = interface{} /* illegal expression */`,
+ `package p; var a = []int /* illegal expression */`,
+ `package p; var a = map[int]int /* illegal expression */`,
+ `package p; var a = chan int; /* illegal expression */`,
+ `package p; var a = []int{[]int}; /* illegal expression */`,
+ `package p; var a = ([]int); /* illegal expression */`,
+ `package p; var a = a[[]int:[]int]; /* illegal expression */`,
+ `package p; var a = <- chan int; /* illegal expression */`,
+ `package p; func f() { select { case _ <- chan int: } };`,
}
-
func TestParseIllegalInputs(t *testing.T) {
for _, src := range illegalInputs {
_, err := ParseFile(fset, "", src, 0)
@@ -34,7 +50,6 @@ func TestParseIllegalInputs(t *testing.T) {
}
}
-
var validPrograms = []interface{}{
"package p\n",
`package p;`,
@@ -54,9 +69,9 @@ var validPrograms = []interface{}{
`package p; func f() { select { case x := (<-c): } };`,
`package p; func f() { if ; true {} };`,
`package p; func f() { switch ; {} };`,
+ `package p; func f() { for _ = range "foo" + "bar" {} };`,
}
-
func TestParseValidPrograms(t *testing.T) {
for _, src := range validPrograms {
_, err := ParseFile(fset, "", src, 0)
@@ -66,13 +81,11 @@ func TestParseValidPrograms(t *testing.T) {
}
}
-
var validFiles = []string{
"parser.go",
"parser_test.go",
}
-
func TestParse3(t *testing.T) {
for _, filename := range validFiles {
_, err := ParseFile(fset, filename, nil, DeclarationErrors)
@@ -82,7 +95,6 @@ func TestParse3(t *testing.T) {
}
}
-
func nameFilter(filename string) bool {
switch filename {
case "parser.go":
@@ -94,10 +106,8 @@ func nameFilter(filename string) bool {
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)
diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go
index 86c32793062..9cd975ec1be 100644
--- a/libgo/go/go/printer/nodes.go
+++ b/libgo/go/go/printer/nodes.go
@@ -14,7 +14,6 @@ import (
"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
@@ -23,7 +22,6 @@ import (
// - 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.
@@ -33,7 +31,7 @@ import (
// 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
+// is preceded 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
@@ -56,7 +54,6 @@ func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (prin
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
@@ -78,7 +75,6 @@ func (p *printer) setComment(g *ast.CommentGroup) {
p.cindex = 0
}
-
type exprListMode uint
const (
@@ -90,7 +86,6 @@ const (
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.
@@ -107,7 +102,6 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
}
-
// 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
@@ -215,12 +209,13 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
if i > 0 {
- if mode&commaSep != 0 {
+ switch {
+ case mode&commaSep != 0:
p.print(token.COMMA)
- }
- if mode&periodSep != 0 {
+ case mode&periodSep != 0:
p.print(token.PERIOD)
}
+ needsBlank := mode&periodSep == 0 // period-separated list elements don't need a blank
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
@@ -229,11 +224,12 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
ws = ignore
*multiLine = true
prevBreak = i
+ needsBlank = false // we got a line break instead
}
- } else if mode&periodSep == 0 {
+ }
+ if needsBlank {
p.print(blank)
}
- // period-separated list elements don't need a blank
}
if isPair && size > 0 && len(list) > 1 {
@@ -269,7 +265,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
}
}
-
// 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)
@@ -300,7 +295,6 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
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)
@@ -316,7 +310,6 @@ func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) {
}
}
-
func identListSize(list []*ast.Ident, maxSize int) (size int) {
for i, x := range list {
if i > 0 {
@@ -330,7 +323,6 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) {
return
}
-
func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
if len(list) != 1 {
return false // allow only one field
@@ -349,18 +341,11 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
return namesSize+typeSize <= maxSize
}
-
func (p *printer) setLineComment(text string) {
p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}})
}
-
func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
- p.nesting++
- defer func() {
- p.nesting--
- }()
-
lbrace := fields.Opening
list := fields.List
rbrace := fields.Closing
@@ -438,8 +423,8 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
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")
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.setLineComment("// contains filtered or unexported fields")
}
} else { // interface
@@ -465,15 +450,14 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
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.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment
+ p.setLineComment("// contains filtered or unexported methods")
}
}
p.print(unindent, formfeed, rbrace, token.RBRACE)
}
-
// ----------------------------------------------------------------------------
// Expressions
@@ -532,7 +516,6 @@ func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
return
}
-
func cutoff(e *ast.BinaryExpr, depth int) int {
has4, has5, maxProblem := walkBinary(e)
if maxProblem > 0 {
@@ -550,7 +533,6 @@ func cutoff(e *ast.BinaryExpr, depth int) int {
return 4
}
-
func diffPrec(expr ast.Expr, prec int) int {
x, ok := expr.(*ast.BinaryExpr)
if !ok || prec != x.Op.Precedence() {
@@ -559,7 +541,6 @@ func diffPrec(expr ast.Expr, prec int) int {
return 0
}
-
func reduceDepth(depth int) int {
depth--
if depth < 1 {
@@ -568,7 +549,6 @@ func reduceDepth(depth int) int {
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.)
@@ -646,13 +626,11 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
}
}
-
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
@@ -692,7 +670,6 @@ func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
return
}
-
// Convert an expression into an expression list split at the periods of
// selector expressions.
func selectorExprList(expr ast.Expr) (list []ast.Expr) {
@@ -711,7 +688,6 @@ func selectorExprList(expr ast.Expr) (list []ast.Expr) {
return
}
-
// Sets multiLine to true if the expression spans multiple lines.
func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
p.print(expr.Pos())
@@ -898,19 +874,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
return
}
-
func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
p.expr1(x, token.LowestPrec, depth, 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, multiLine)
}
-
// ----------------------------------------------------------------------------
// Statements
@@ -935,7 +908,6 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
}
}
-
// 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)
@@ -944,7 +916,6 @@ func (p *printer) block(s *ast.BlockStmt, indent int) {
p.print(s.Rbrace, token.RBRACE)
}
-
func isTypeName(x ast.Expr) bool {
switch t := x.(type) {
case *ast.Ident:
@@ -955,7 +926,6 @@ func isTypeName(x ast.Expr) bool {
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
@@ -982,7 +952,6 @@ func stripParens(x ast.Expr) ast.Expr {
return x
}
-
func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
p.print(blank)
needsBlank := false
@@ -1017,7 +986,6 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
}
}
-
// 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())
@@ -1156,8 +1124,14 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
case *ast.SelectStmt:
p.print(token.SELECT, blank)
- p.block(s.Body, 0)
- *multiLine = true
+ body := s.Body
+ if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) {
+ // print empty select statement w/o comments on one line
+ p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
+ } else {
+ p.block(body, 0)
+ *multiLine = true
+ }
case *ast.ForStmt:
p.print(token.FOR)
@@ -1185,10 +1159,98 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
return
}
-
// ----------------------------------------------------------------------------
// Declarations
+// The keepTypeColumn function determines if the type column of a series of
+// consecutive const or var declarations must be kept, or if initialization
+// values (V) can be placed in the type column (T) instead. The i'th entry
+// in the result slice is true if the type column in spec[i] must be kept.
+//
+// For example, the declaration:
+//
+// const (
+// foobar int = 42 // comment
+// x = 7 // comment
+// foo
+// bar = 991
+// )
+//
+// leads to the type/values matrix below. A run of value columns (V) can
+// be moved into the type column if there is no type for any of the values
+// in that column (we only move entire columns so that they align properly).
+//
+// matrix formatted result
+// matrix
+// T V -> T V -> true there is a T and so the type
+// - V - V true column must be kept
+// - - - - false
+// - V V - false V is moved into T column
+//
+func keepTypeColumn(specs []ast.Spec) []bool {
+ m := make([]bool, len(specs))
+
+ populate := func(i, j int, keepType bool) {
+ if keepType {
+ for ; i < j; i++ {
+ m[i] = true
+ }
+ }
+ }
+
+ i0 := -1 // if i0 >= 0 we are in a run and i0 is the start of the run
+ var keepType bool
+ for i, s := range specs {
+ t := s.(*ast.ValueSpec)
+ if t.Values != nil {
+ if i0 < 0 {
+ // start of a run of ValueSpecs with non-nil Values
+ i0 = i
+ keepType = false
+ }
+ } else {
+ if i0 >= 0 {
+ // end of a run
+ populate(i0, i, keepType)
+ i0 = -1
+ }
+ }
+ if t.Type != nil {
+ keepType = true
+ }
+ }
+ if i0 >= 0 {
+ // end of a run
+ populate(i0, len(specs), keepType)
+ }
+
+ return m
+}
+
+func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) {
+ p.setComment(s.Doc)
+ p.identList(s.Names, doIndent, multiLine) // always present
+ extraTabs := 3
+ if s.Type != nil || keepType {
+ p.print(vtab)
+ extraTabs--
+ }
+ if s.Type != nil {
+ p.expr(s.Type, multiLine)
+ }
+ 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)
+ }
+}
+
// 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.
@@ -1206,38 +1268,20 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
p.setComment(s.Comment)
case *ast.ValueSpec:
+ if n != 1 {
+ p.internalError("expected n = 1; got", n)
+ }
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)
- }
+ 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)
case *ast.TypeSpec:
p.setComment(s.Doc)
@@ -1255,7 +1299,6 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
}
}
-
// Sets multiLine to true if the declaration spans multiple lines.
func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
p.setComment(d.Doc)
@@ -1264,15 +1307,29 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
if d.Lparen.IsValid() {
// group of parenthesized declarations
p.print(d.Lparen, token.LPAREN)
- if len(d.Specs) > 0 {
+ if n := len(d.Specs); n > 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)
+ if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
+ // two or more grouped const/var declarations:
+ // determine if the type column must be kept
+ keepType := keepTypeColumn(d.Specs)
+ 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.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml)
+ }
+ } else {
+ 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, n, false, &ml)
}
- ml = false
- p.spec(s, len(d.Specs), false, &ml)
}
p.print(unindent, formfeed)
*multiLine = true
@@ -1285,7 +1342,6 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
}
}
-
// 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
@@ -1303,7 +1359,7 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
size = maxSize + 1 // assume n doesn't fit
p.nodeSizes[n] = size
- // nodeSize computation must be indendent of particular
+ // nodeSize computation must be independent of particular
// style so that we always get the same decision; print
// in RawFormat
cfg := Config{Mode: RawFormat}
@@ -1323,7 +1379,6 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
return
}
-
func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
pos1 := b.Pos()
pos2 := b.Rbrace
@@ -1347,18 +1402,12 @@ func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool {
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 {
@@ -1384,7 +1433,6 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
*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.
@@ -1396,7 +1444,6 @@ func (p *printer) distance(from0 token.Pos, to token.Position) int {
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)
@@ -1410,7 +1457,6 @@ func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
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) {
@@ -1425,7 +1471,6 @@ func (p *printer) decl(decl ast.Decl, multiLine *bool) {
}
}
-
// ----------------------------------------------------------------------------
// Files
@@ -1440,7 +1485,6 @@ func declToken(decl ast.Decl) (tok token.Token) {
return
}
-
func (p *printer) file(src *ast.File) {
p.setComment(src.Doc)
p.print(src.Pos(), token.PACKAGE, blank)
diff --git a/libgo/go/go/printer/performance_test.go b/libgo/go/go/printer/performance_test.go
index 31de0b7ad40..84fb2808eba 100644
--- a/libgo/go/go/printer/performance_test.go
+++ b/libgo/go/go/printer/performance_test.go
@@ -17,17 +17,14 @@ import (
"testing"
)
-
var testfile *ast.File
-
func testprint(out io.Writer, file *ast.File) {
if _, err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil {
log.Fatalf("print error: %s", err)
}
}
-
// cannot initialize in init because (printer) Fprint launches goroutines.
func initialize() {
const filename = "testdata/parser.go"
@@ -51,7 +48,6 @@ func initialize() {
testfile = file
}
-
func BenchmarkPrint(b *testing.B) {
if testfile == nil {
initialize()
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index 01ebf783c41..871fefa0c8f 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -17,7 +17,6 @@ import (
"tabwriter"
)
-
const debug = false // enable for debugging
@@ -33,7 +32,6 @@ const (
unindent = whiteSpace('<')
)
-
var (
esc = []byte{tabwriter.Escape}
htab = []byte{'\t'}
@@ -42,16 +40,13 @@ var (
formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
)
-
// Special positions
var noPos token.Position // use noPos when a position is needed but not known
var infinity = 1 << 30
-
// Use ignoreMultiLine if the multiLine information is not important.
var ignoreMultiLine = new(bool)
-
// A pmode value represents the current printer mode.
type pmode int
@@ -60,7 +55,6 @@ const (
noExtraLinebreak
)
-
type printer struct {
// Configuration (does not change after initialization)
output io.Writer
@@ -69,7 +63,6 @@ type printer struct {
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
@@ -98,7 +91,6 @@ type printer struct {
nodeSizes map[ast.Node]int
}
-
func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) {
p.output = output
p.Config = *cfg
@@ -108,7 +100,6 @@ func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeS
p.nodeSizes = nodeSizes
}
-
func (p *printer) internalError(msg ...interface{}) {
if debug {
fmt.Print(p.pos.String() + ": ")
@@ -117,7 +108,6 @@ func (p *printer) internalError(msg ...interface{}) {
}
}
-
// escape escapes string s by bracketing it with tabwriter.Escape.
// Escaped strings pass through tabwriter unchanged. (Note that
// valid Go programs cannot contain tabwriter.Escape bytes since
@@ -131,26 +121,20 @@ func (p *printer) escape(s string) string {
return p.litbuf.String()
}
-
// 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.
+// of breaks n such that min <= result <= max.
//
func (p *printer) nlines(n, min int) int {
- if n < min {
+ const max = 2 // max. number of newlines
+ switch {
+ case 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 {
+ case 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.
//
@@ -165,7 +149,6 @@ func (p *printer) write0(data []byte) {
}
}
-
// write interprets data and writes it to p.output. It inserts indentation
// after a line break unless in a tabwriter escape sequence.
// It updates p.pos as a side-effect.
@@ -220,7 +203,6 @@ func (p *printer) write(data []byte) {
p.pos.Column += d
}
-
func (p *printer) writeNewlines(n int, useFF bool) {
if n > 0 {
n = p.nlines(n, 0)
@@ -232,7 +214,6 @@ func (p *printer) writeNewlines(n int, useFF bool) {
}
}
-
// 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
@@ -261,7 +242,6 @@ func (p *printer) writeItem(pos token.Position, data string) {
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.
@@ -368,7 +348,6 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
}
}
-
// TODO(gri): It should be possible to convert the code below from using
// []byte to string and in the process eliminate some conversions.
@@ -398,7 +377,6 @@ func split(text []byte) [][]byte {
return lines
}
-
func isBlank(s []byte) bool {
for _, b := range s {
if b > ' ' {
@@ -408,7 +386,6 @@ func isBlank(s []byte) bool {
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] == '*') {
@@ -417,7 +394,6 @@ func commonPrefix(a, b []byte) []byte {
return a[0:i]
}
-
func stripCommonPrefix(lines [][]byte) {
if len(lines) < 2 {
return // at most one line - nothing to do
@@ -545,7 +521,6 @@ func stripCommonPrefix(lines [][]byte) {
}
}
-
func (p *printer) writeComment(comment *ast.Comment) {
text := comment.Text
@@ -575,7 +550,6 @@ func (p *printer) writeComment(comment *ast.Comment) {
}
}
-
// 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
@@ -589,7 +563,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
// ignore trailing whitespace
p.wsbuf[i] = ignore
case indent, unindent:
- // don't loose indentation information
+ // don't lose indentation information
case newline, formfeed:
// if we need a line break, keep exactly one
// but remember if we dropped any formfeeds
@@ -613,7 +587,6 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
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
@@ -651,7 +624,6 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
return false
}
-
// whiteWhitespace writes the first n whitespace entries.
func (p *printer) writeWhitespace(n int) {
// write entries
@@ -701,7 +673,6 @@ func (p *printer) writeWhitespace(n int) {
p.wsbuf = p.wsbuf[0:i]
}
-
// ----------------------------------------------------------------------------
// Printing interface
@@ -724,7 +695,6 @@ func mayCombine(prev token.Token, next byte) (b bool) {
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
@@ -812,7 +782,6 @@ func (p *printer) print(args ...interface{}) {
}
}
-
// commentBefore returns true iff the current comment occurs
// before the next position in the source code.
//
@@ -820,7 +789,6 @@ 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
@@ -838,7 +806,6 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
return
}
-
// ----------------------------------------------------------------------------
// Trimmer
@@ -854,7 +821,6 @@ type trimmer struct {
space bytes.Buffer
}
-
// trimmer is implemented as a state machine.
// It can be in one of the following states:
const (
@@ -863,7 +829,6 @@ const (
inText // inside text
)
-
// 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.
@@ -941,7 +906,6 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) {
return
}
-
// ----------------------------------------------------------------------------
// Public interface
@@ -952,14 +916,12 @@ const (
UseSpaces // use spaces instead of tabs for alignment
)
-
// A Config node controls the output of Fprint.
type Config struct {
Mode uint // default: 0
Tabwidth int // default: 8
}
-
// fprint implements Fprint and takes a nodesSizes map for setting up the printer state.
func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (int, os.Error) {
// redirect output through a trimmer to eliminate trailing whitespace
@@ -994,11 +956,9 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
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".
@@ -1007,15 +967,12 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
}
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)
@@ -1036,7 +993,6 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
return p.written, err
}
-
// 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.
@@ -1047,7 +1003,6 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{
return cfg.fprint(output, fset, node, make(map[ast.Node]int))
}
-
// Fprint "pretty-prints" an AST node to output.
// It calls Config.Fprint with default settings.
//
diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go
index 090f92af181..ff2d906b560 100644
--- a/libgo/go/go/printer/printer_test.go
+++ b/libgo/go/go/printer/printer_test.go
@@ -16,19 +16,15 @@ import (
"time"
)
-
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' {
@@ -37,7 +33,6 @@ func lineString(text []byte, i int) string {
return string(text[i0:i])
}
-
type checkMode uint
const (
@@ -45,7 +40,6 @@ const (
rawFormat
)
-
func runcheck(t *testing.T, source, golden string, mode checkMode) {
// parse source
prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
@@ -109,7 +103,6 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) {
}
}
-
func check(t *testing.T, source, golden string, mode checkMode) {
// start a timer to produce a time-out signal
tc := make(chan int)
@@ -135,7 +128,6 @@ func check(t *testing.T, source, golden string, mode checkMode) {
}
}
-
type entry struct {
source, golden string
mode checkMode
@@ -154,7 +146,6 @@ var data = []entry{
{"slow.input", "slow.golden", 0},
}
-
func TestFiles(t *testing.T) {
for i, e := range data {
source := filepath.Join(dataDir, e.source)
@@ -168,7 +159,6 @@ func TestFiles(t *testing.T) {
}
}
-
// TestLineComments, using a simple test case, checks that consequtive line
// comments are properly terminated with a newline even if the AST position
// information is incorrect.
diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden
index a86d6617432..7b332252c4e 100644
--- a/libgo/go/go/printer/testdata/comments.golden
+++ b/libgo/go/go/printer/testdata/comments.golden
@@ -22,7 +22,7 @@ const (
_ = iota + 10
_ // comments
- _ = 10 // comment
+ _ = 10 // comment
_ T = 20 // comment
)
@@ -38,9 +38,9 @@ const (
_ // comment
_ // comment
_ = iota + 10
- _ // comment
- _ = 10
- _ = 20 // comment
+ _ // comment
+ _ = 10
+ _ = 20 // comment
_ T = 0 // comment
)
@@ -106,7 +106,6 @@ type S3 struct {
var x int // x
var ()
-
// This comment SHOULD be associated with the next declaration.
func f0() {
const pi = 3.14 // pi
@@ -128,12 +127,10 @@ func f1() {
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
@@ -144,7 +141,6 @@ func _(x int) int {
return x
}
-
func typeswitch(x interface{}) {
switch v := x.(type) {
case bool, int, float:
@@ -211,7 +207,6 @@ func _() {
aligned line */
}
-
func _() {
/*
freestanding comment
@@ -292,7 +287,6 @@ func _() {
aligned line */
}
-
func _() {
/*
freestanding comment
@@ -409,7 +403,6 @@ func _() {
*/
}
-
// Some interesting interspersed comments
func _( /* this */ x /* is */ /* an */ int) {
}
@@ -434,9 +427,8 @@ 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.
+// may only have estimated position information) must remain after the punctuation.
func _() {
_ = T{
1, // comment after comma
@@ -466,7 +458,6 @@ func _() {
}
}
-
// Line comments with tabs
func _() {
var finput *bufio.Reader // input file
@@ -479,5 +470,4 @@ func _() {
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
index 14cd4cf7a12..2a9a86b6815 100644
--- a/libgo/go/go/printer/testdata/comments.input
+++ b/libgo/go/go/printer/testdata/comments.input
@@ -434,7 +434,7 @@ func _() {
// Comments immediately adjacent to punctuation (for which the go/printer
-// may obly have estimated position information) must remain after the punctuation.
+// may only have estimated position information) must remain after the punctuation.
func _() {
_ = T{
1, // comment after comma
diff --git a/libgo/go/go/printer/testdata/comments.x b/libgo/go/go/printer/testdata/comments.x
index 4d7a928ae09..ae7729286e5 100644
--- a/libgo/go/go/printer/testdata/comments.x
+++ b/libgo/go/go/printer/testdata/comments.x
@@ -2,13 +2,12 @@
//
package main
-
// The SZ struct; it is empty.
type SZ struct{}
// The S0 struct; no field is exported.
type S0 struct {
- // contains unexported fields
+ // contains filtered or unexported fields
}
// The S1 struct; some fields are not exported.
@@ -16,7 +15,7 @@ type S1 struct {
S0
A, B, C float // 3 exported fields
D int // 2 unexported fields
- // contains unexported fields
+ // contains filtered or unexported fields
}
// The S2 struct; all fields are exported.
@@ -30,14 +29,14 @@ type SZ interface{}
// The I0 interface; no method is exported.
type I0 interface {
- // contains unexported methods
+ // contains filtered or unexported methods
}
// The I1 interface; some methods are not exported.
type I1 interface {
I0
F(x float) float // exported methods
- // contains unexported methods
+ // contains filtered or unexported methods
}
// The I2 interface; all methods are exported.
@@ -53,5 +52,5 @@ type S3 struct {
F1 int // line comment for F1
// lead comment for F2
F2 int // line comment for F2
- // contains unexported fields
+ // contains filtered or unexported fields
}
diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden
index c1b255842c1..970533e8cfb 100644
--- a/libgo/go/go/printer/testdata/declarations.golden
+++ b/libgo/go/go/printer/testdata/declarations.golden
@@ -44,7 +44,6 @@ import _ "os"
import _ "os"
import _ "os"
-
import _ "fmt"
import _ "fmt"
import _ "fmt"
@@ -116,7 +115,6 @@ import _ "io"
var _ int
-
// printing of constant literals
const (
_ = "foobar"
@@ -158,9 +156,7 @@ const (
bar`
)
-
func _() {
- // the following decls need a semicolon at the end
type _ int
type _ *int
type _ []int
@@ -175,7 +171,6 @@ func _() {
var _ chan int
var _ func() int
- // the following decls don't need a semicolon at the end
type _ struct{}
type _ *struct{}
type _ []struct{}
@@ -205,7 +200,6 @@ func _() {
var _ func() interface{}
}
-
// don't lose blank lines in grouped declarations
const (
_ int = 0
@@ -222,7 +216,6 @@ const (
_
)
-
type (
_ int
_ struct{}
@@ -233,7 +226,6 @@ type (
_ map[string]int
)
-
var (
_ int = 0
_ float = 1
@@ -246,7 +238,6 @@ var (
_ bool
)
-
// don't lose blank lines in this struct
type _ struct {
String struct {
@@ -295,7 +286,6 @@ type _ struct {
}
}
-
// no tabs for single or ungrouped decls
func _() {
const xxxxxx = 0
@@ -331,11 +321,11 @@ func _() {
)
// some entries have a type
const (
- xxxxxx = 1
- x = 2
- xxx = 3
+ xxxxxx = 1
+ x = 2
+ xxx = 3
yyyyyyyy float = iota
- yyyy = "bar"
+ yyyy = "bar"
yyy
yy = 2
)
@@ -365,7 +355,7 @@ func _() {
xxx string
yyyyyyyy int = 1234
y float = 3.14
- yyyy = "bar"
+ yyyy = "bar"
yyy string = "foo"
)
// mixed entries - all comments should be aligned
@@ -373,7 +363,7 @@ func _() {
a, b, c int
x = 10
d int // comment
- y = 20 // comment
+ y = 20 // comment
f, ff, fff, ffff int = 0, 1, 2, 3 // comment
)
// respect original line breaks
@@ -401,6 +391,32 @@ func _() {
)
}
+// alignment of "=" in consecutive lines (extended example from issue 1414)
+const (
+ umax uint = ^uint(0) // maximum value for a uint
+ bpu = 1 << (5 + umax>>63) // bits per uint
+ foo
+ bar = -1
+)
+
+// typical enum
+const (
+ a MyType = iota
+ abcd
+ b
+ c
+ def
+)
+
+// excerpt from godoc.go
+var (
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+ testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
+ filter = flag.String("filter", "", "filter file containing permitted package directory paths")
+ filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
+ filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
+)
// formatting of structs
type _ struct{}
@@ -469,14 +485,12 @@ type _ struct {
r, s float // this line should be indented
}
-
// difficult cases
type _ struct {
bool // comment
text []byte // comment
}
-
// formatting of interfaces
type EI interface{}
@@ -502,7 +516,6 @@ type _ interface { // this comment must not change indentation
gggggggggggg(x, y, z int) // hurray
}
-
// formatting of variable declarations
func _() {
type day struct {
@@ -520,7 +533,6 @@ func _() {
)
}
-
// formatting of multi-line variable declarations
var a1, b1, c1 int // all on one line
@@ -533,7 +545,6 @@ var (
a4, b4, c4 int // this line should be indented
)
-
func _() {
var privateKey2 = &Block{Type: "RSA PRIVATE KEY",
Headers: map[string]string{},
@@ -545,7 +556,6 @@ func _() {
}
}
-
func _() {
var Universe = Scope{
Names: map[string]*Ident{
@@ -589,7 +599,6 @@ func _() {
}
}
-
// alignment of map composite entries
var _ = map[int]int{
// small key sizes: always align even if size ratios are large
@@ -613,21 +622,18 @@ var _ = map[int]int{
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 _() {}
@@ -655,7 +661,6 @@ func _() int {
return x
}
-
// making function declarations safe for new semicolon rules
func _() { /* multi-line func because of comment */
}
@@ -664,7 +669,6 @@ func _() {
/* multi-line func because block is on multiple lines */
}
-
// ellipsis parameters
func _(...int)
func _(...*int)
@@ -686,7 +690,6 @@ 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) {
diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input
index c8b37e12ba4..c6134096bf1 100644
--- a/libgo/go/go/printer/testdata/declarations.input
+++ b/libgo/go/go/printer/testdata/declarations.input
@@ -159,7 +159,6 @@ bar`
func _() {
- // the following decls need a semicolon at the end
type _ int
type _ *int
type _ []int
@@ -174,7 +173,6 @@ func _() {
var _ chan int
var _ func() int
- // the following decls don't need a semicolon at the end
type _ struct{}
type _ *struct{}
type _ []struct{}
@@ -400,6 +398,33 @@ func _() {
)
}
+// alignment of "=" in consecutive lines (extended example from issue 1414)
+const (
+ umax uint = ^uint(0) // maximum value for a uint
+ bpu = 1 << (5 + umax>>63) // bits per uint
+ foo
+ bar = -1
+)
+
+// typical enum
+const (
+ a MyType = iota
+ abcd
+ b
+ c
+ def
+)
+
+// excerpt from godoc.go
+var (
+ goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+ testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
+ filter = flag.String("filter", "", "filter file containing permitted package directory paths")
+ filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
+ filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
+)
+
// formatting of structs
type _ struct{}
diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden
index 3d0f144e10f..d0cf24ad6f6 100644
--- a/libgo/go/go/printer/testdata/expressions.golden
+++ b/libgo/go/go/printer/testdata/expressions.golden
@@ -17,7 +17,6 @@ var (
p *int
)
-
func _() {
// no spaces around simple or parenthesized expressions
_ = (a + 0)
@@ -115,7 +114,6 @@ func _() {
x < y || z > 42
}
-
func _() {
_ = a + b
_ = a + b + c
@@ -187,7 +185,6 @@ func _() {
_ = token(matchType + xlength<<lengthShift + xoffset)
}
-
func f(x int, args ...int) {
f(0, args...)
f(1, args)
@@ -226,7 +223,6 @@ func f(x int, args ...int) {
_ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
}
-
func _() {
_ = T{}
_ = struct{}{}
@@ -236,7 +232,6 @@ func _() {
_ = map[int]T{}
}
-
// one-line structs/interfaces in composite literals (up to a threshold)
func _() {
_ = struct{}{}
@@ -246,7 +241,6 @@ func _() {
_ = struct{ s struct{ int } }{struct{ int }{0}}
}
-
func _() {
// do not modify literals
_ = "tab1 tab2 tab3 end" // string contains 3 tabs
@@ -261,7 +255,6 @@ func _() {
they must not be removed`
}
-
func _() {
// smart handling of indentation for multi-line raw strings
var _ = ``
@@ -332,7 +325,6 @@ bar`
}
}
-
func _() {
// one-line function literals (body is on a single line)
_ = func() {}
@@ -361,7 +353,6 @@ func _() {
})
}
-
func _() {
_ = [][]int{
[]int{1},
@@ -381,7 +372,6 @@ func _() {
_ = [][]int{{1}, {1, 2}, {1, 2, 3}}
}
-
// various multi-line expressions
func _() {
// do not add extra indentation to multi-line string lists
@@ -397,25 +387,21 @@ func _() {
}
}
-
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";` +
@@ -434,7 +420,6 @@ func _() {
`datafmt.T3 = s {" " a a / ","};`
}
-
func _() {
// respect source lines in multi-line expressions
_ = a +
@@ -448,7 +433,6 @@ func _() {
_ = "170141183460469231731687303715884105727" // prime
}
-
// Alignment after overlong lines
const (
_ = "991"
@@ -459,7 +443,6 @@ const (
_ = "170141183460469231731687303715884105727" // prime
)
-
// Correct placement of operators and comments in multi-line expressions
func _() {
_ = a + // comment
@@ -471,7 +454,6 @@ func _() {
_ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
}
-
// Correct placement of terminating comma/closing parentheses in multi-line calls.
func _() {
f(1,
@@ -497,7 +479,6 @@ func _() {
)
}
-
// Align comments in multi-line lists of single-line expressions.
var txpix = [NCOL]draw.Color{
draw.Yellow, // yellow
@@ -512,7 +493,6 @@ var txpix = [NCOL]draw.Color{
draw.Color(0xBB005DFF), /* maroon */
}
-
func same(t, u *Time) bool {
// respect source lines in multi-line expressions
return t.Year == u.Year &&
@@ -526,7 +506,6 @@ func same(t, u *Time) bool {
t.Zone == u.Zone
}
-
func (p *parser) charClass() {
// respect source lines in multi-line expressions
if cc.negate && len(cc.ranges) == 2 &&
@@ -536,7 +515,6 @@ func (p *parser) charClass() {
}
}
-
func addState(s []state, inst instr, match []int) {
// handle comments correctly in multi-line expressions
for i := 0; i < l; i++ {
@@ -639,12 +617,11 @@ func _() {
c
}
-
// Don't introduce extra newlines in strangely formatted expression lists.
func f() {
// os.Open parameters should remain on two lines
if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
- os.O_TRUNC,0666); err != nil {
+ os.O_TRUNC, 0666); err != nil {
log.Fatal(err)
}
}
diff --git a/libgo/go/go/printer/testdata/expressions.raw b/libgo/go/go/printer/testdata/expressions.raw
index 72ab850fab4..d7819a3baad 100644
--- a/libgo/go/go/printer/testdata/expressions.raw
+++ b/libgo/go/go/printer/testdata/expressions.raw
@@ -17,7 +17,6 @@ var (
p *int
)
-
func _() {
// no spaces around simple or parenthesized expressions
_ = (a + 0)
@@ -115,7 +114,6 @@ func _() {
x < y || z > 42
}
-
func _() {
_ = a + b
_ = a + b + c
@@ -187,7 +185,6 @@ func _() {
_ = token(matchType + xlength<<lengthShift + xoffset)
}
-
func f(x int, args ...int) {
f(0, args...)
f(1, args)
@@ -226,7 +223,6 @@ func f(x int, args ...int) {
_ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
}
-
func _() {
_ = T{}
_ = struct{}{}
@@ -236,7 +232,6 @@ func _() {
_ = map[int]T{}
}
-
// one-line structs/interfaces in composite literals (up to a threshold)
func _() {
_ = struct{}{}
@@ -246,7 +241,6 @@ func _() {
_ = struct{ s struct{ int } }{struct{ int }{0}}
}
-
func _() {
// do not modify literals
_ = "tab1 tab2 tab3 end" // string contains 3 tabs
@@ -261,7 +255,6 @@ func _() {
they must not be removed`
}
-
func _() {
// smart handling of indentation for multi-line raw strings
var _ = ``
@@ -332,7 +325,6 @@ bar`
}
}
-
func _() {
// one-line function literals (body is on a single line)
_ = func() {}
@@ -361,7 +353,6 @@ func _() {
})
}
-
func _() {
_ = [][]int{
[]int{1},
@@ -381,7 +372,6 @@ func _() {
_ = [][]int{{1}, {1, 2}, {1, 2, 3}}
}
-
// various multi-line expressions
func _() {
// do not add extra indentation to multi-line string lists
@@ -397,25 +387,21 @@ func _() {
}
}
-
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";` +
@@ -434,7 +420,6 @@ func _() {
`datafmt.T3 = s {" " a a / ","};`
}
-
func _() {
// respect source lines in multi-line expressions
_ = a +
@@ -448,7 +433,6 @@ func _() {
_ = "170141183460469231731687303715884105727" // prime
}
-
// Alignment after overlong lines
const (
_ = "991"
@@ -459,7 +443,6 @@ const (
_ = "170141183460469231731687303715884105727" // prime
)
-
// Correct placement of operators and comments in multi-line expressions
func _() {
_ = a + // comment
@@ -471,7 +454,6 @@ func _() {
_ = "ba0408" + "7265717569726564" // field 71, encoding 2, string "required"
}
-
// Correct placement of terminating comma/closing parentheses in multi-line calls.
func _() {
f(1,
@@ -497,7 +479,6 @@ func _() {
)
}
-
// Align comments in multi-line lists of single-line expressions.
var txpix = [NCOL]draw.Color{
draw.Yellow, // yellow
@@ -512,7 +493,6 @@ var txpix = [NCOL]draw.Color{
draw.Color(0xBB005DFF), /* maroon */
}
-
func same(t, u *Time) bool {
// respect source lines in multi-line expressions
return t.Year == u.Year &&
@@ -526,7 +506,6 @@ func same(t, u *Time) bool {
t.Zone == u.Zone
}
-
func (p *parser) charClass() {
// respect source lines in multi-line expressions
if cc.negate && len(cc.ranges) == 2 &&
@@ -536,7 +515,6 @@ func (p *parser) charClass() {
}
}
-
func addState(s []state, inst instr, match []int) {
// handle comments correctly in multi-line expressions
for i := 0; i < l; i++ {
@@ -639,12 +617,11 @@ func _() {
c
}
-
// Don't introduce extra newlines in strangely formatted expression lists.
func f() {
// os.Open parameters should remain on two lines
if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
- os.O_TRUNC,0666); err != nil {
+ os.O_TRUNC, 0666); err != nil {
log.Fatal(err)
}
}
diff --git a/libgo/go/go/printer/testdata/parser.go b/libgo/go/go/printer/testdata/parser.go
index 5c57e41d130..2d27af49920 100644
--- a/libgo/go/go/printer/testdata/parser.go
+++ b/libgo/go/go/printer/testdata/parser.go
@@ -16,7 +16,6 @@ import (
"go/token"
)
-
// 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.
@@ -29,7 +28,6 @@ const (
DeclarationErrors // report declaration errors
)
-
// The parser structure holds the parser's internal state.
type parser struct {
file *token.File
@@ -66,7 +64,6 @@ type parser struct {
targetStack [][]*ast.Ident // stack of unresolved labels
}
-
// scannerMode returns the scanner mode bits given the parser's mode bits.
func scannerMode(mode uint) uint {
var m uint = scanner.InsertSemis
@@ -76,7 +73,6 @@ func scannerMode(mode uint) uint {
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))
@@ -95,7 +91,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin
p.openLabelScope()
}
-
// ----------------------------------------------------------------------------
// Scoping support
@@ -103,18 +98,15 @@ func (p *parser) openScope() {
p.topScope = ast.NewScope(p.topScope)
}
-
func (p *parser) closeScope() {
p.topScope = p.topScope.Outer
}
-
func (p *parser) openLabelScope() {
p.labelScope = ast.NewScope(p.labelScope)
p.targetStack = append(p.targetStack, nil)
}
-
func (p *parser) closeLabelScope() {
// resolve labels
n := len(p.targetStack) - 1
@@ -130,7 +122,6 @@ func (p *parser) closeLabelScope() {
p.labelScope = p.labelScope.Outer
}
-
func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
for _, ident := range idents {
assert(ident.Obj == nil, "identifier already declared or resolved")
@@ -151,7 +142,6 @@ func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, i
}
}
-
func (p *parser) shortVarDecl(idents []*ast.Ident) {
// Go spec: A short variable declaration may redeclare variables
// provided they were originally declared in the same block with
@@ -177,13 +167,11 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) {
}
}
-
// The unresolved object is a sentinel to mark identifiers that have been added
// to the list of unresolved identifiers. The sentinel is only used for verifying
// internal consistency.
var unresolved = new(ast.Object)
-
func (p *parser) resolve(x ast.Expr) {
// nothing to do if x is not an identifier or the blank identifier
ident, _ := x.(*ast.Ident)
@@ -209,7 +197,6 @@ func (p *parser) resolve(x ast.Expr) {
p.unresolved = append(p.unresolved, ident)
}
-
// ----------------------------------------------------------------------------
// Parsing support
@@ -227,21 +214,18 @@ func (p *parser) printTrace(a ...interface{}) {
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
@@ -283,7 +267,6 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
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
@@ -305,7 +288,6 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
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.
@@ -356,12 +338,10 @@ func (p *parser) next() {
}
}
-
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 {
@@ -379,7 +359,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
p.error(pos, msg)
}
-
func (p *parser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
@@ -389,21 +368,18 @@ func (p *parser) expect(tok token.Token) token.Pos {
return pos
}
-
func (p *parser) expectSemi() {
if p.tok != token.RPAREN && p.tok != token.RBRACE {
p.expect(token.SEMICOLON)
}
}
-
func assert(cond bool, msg string) {
if !cond {
panic("go/parser internal error: " + msg)
}
}
-
// ----------------------------------------------------------------------------
// Identifiers
@@ -419,7 +395,6 @@ func (p *parser) parseIdent() *ast.Ident {
return &ast.Ident{pos, name, nil}
}
-
func (p *parser) parseIdentList() (list []*ast.Ident) {
if p.trace {
defer un(trace(p, "IdentList"))
@@ -434,7 +409,6 @@ func (p *parser) parseIdentList() (list []*ast.Ident) {
return
}
-
// ----------------------------------------------------------------------------
// Common productions
@@ -453,7 +427,6 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
return
}
-
func (p *parser) parseLhsList() []ast.Expr {
list := p.parseExprList(true)
switch p.tok {
@@ -477,12 +450,10 @@ func (p *parser) parseLhsList() []ast.Expr {
return list
}
-
func (p *parser) parseRhsList() []ast.Expr {
return p.parseExprList(false)
}
-
// ----------------------------------------------------------------------------
// Types
@@ -503,7 +474,6 @@ func (p *parser) parseType() ast.Expr {
return typ
}
-
// If the result is an identifier, it is not resolved.
func (p *parser) parseTypeName() ast.Expr {
if p.trace {
@@ -524,7 +494,6 @@ func (p *parser) parseTypeName() ast.Expr {
return ident
}
-
func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "ArrayType"))
@@ -544,7 +513,6 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
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 {
@@ -559,7 +527,6 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
return idents
}
-
func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "FieldDecl"))
@@ -601,7 +568,6 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
return field
}
-
func (p *parser) parseStructType() *ast.StructType {
if p.trace {
defer un(trace(p, "StructType"))
@@ -623,7 +589,6 @@ func (p *parser) parseStructType() *ast.StructType {
return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
-
func (p *parser) parsePointerType() *ast.StarExpr {
if p.trace {
defer un(trace(p, "PointerType"))
@@ -635,7 +600,6 @@ func (p *parser) parsePointerType() *ast.StarExpr {
return &ast.StarExpr{star, base}
}
-
func (p *parser) tryVarType(isParam bool) ast.Expr {
if isParam && p.tok == token.ELLIPSIS {
pos := p.pos
@@ -653,7 +617,6 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
return p.tryIdentOrType(false)
}
-
func (p *parser) parseVarType(isParam bool) ast.Expr {
typ := p.tryVarType(isParam)
if typ == nil {
@@ -665,7 +628,6 @@ func (p *parser) parseVarType(isParam bool) ast.Expr {
return typ
}
-
func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
if p.trace {
defer un(trace(p, "VarList"))
@@ -693,7 +655,6 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
return
}
-
func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
if p.trace {
defer un(trace(p, "ParameterList"))
@@ -738,7 +699,6 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
return
}
-
func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
if p.trace {
defer un(trace(p, "Parameters"))
@@ -754,7 +714,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
return &ast.FieldList{lparen, params, rparen}
}
-
func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
if p.trace {
defer un(trace(p, "Result"))
@@ -774,7 +733,6 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
return nil
}
-
func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
if p.trace {
defer un(trace(p, "Signature"))
@@ -786,7 +744,6 @@ func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldLis
return
}
-
func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
if p.trace {
defer un(trace(p, "FuncType"))
@@ -799,7 +756,6 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
return &ast.FuncType{pos, params, results}, scope
}
-
func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "MethodSpec"))
@@ -827,7 +783,6 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field {
return spec
}
-
func (p *parser) parseInterfaceType() *ast.InterfaceType {
if p.trace {
defer un(trace(p, "InterfaceType"))
@@ -846,7 +801,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
-
func (p *parser) parseMapType() *ast.MapType {
if p.trace {
defer un(trace(p, "MapType"))
@@ -861,7 +815,6 @@ func (p *parser) parseMapType() *ast.MapType {
return &ast.MapType{pos, key, value}
}
-
func (p *parser) parseChanType() *ast.ChanType {
if p.trace {
defer un(trace(p, "ChanType"))
@@ -885,7 +838,6 @@ func (p *parser) parseChanType() *ast.ChanType {
return &ast.ChanType{pos, dir, value}
}
-
// If the result is an identifier, it is not resolved.
func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
switch p.tok {
@@ -918,7 +870,6 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
return nil
}
-
func (p *parser) tryType() ast.Expr {
typ := p.tryIdentOrType(false)
if typ != nil {
@@ -927,7 +878,6 @@ func (p *parser) tryType() ast.Expr {
return typ
}
-
// ----------------------------------------------------------------------------
// Blocks
@@ -943,7 +893,6 @@ func (p *parser) parseStmtList() (list []ast.Stmt) {
return
}
-
func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
if p.trace {
defer un(trace(p, "Body"))
@@ -960,7 +909,6 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
return &ast.BlockStmt{lbrace, list, rbrace}
}
-
func (p *parser) parseBlockStmt() *ast.BlockStmt {
if p.trace {
defer un(trace(p, "BlockStmt"))
@@ -975,7 +923,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
return &ast.BlockStmt{lbrace, list, rbrace}
}
-
// ----------------------------------------------------------------------------
// Expressions
@@ -997,7 +944,6 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
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.
// If lhs is set and the result is an identifier, it is not resolved.
@@ -1047,7 +993,6 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
return &ast.BadExpr{pos, p.pos}
}
-
func (p *parser) parseSelector(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "Selector"))
@@ -1058,7 +1003,6 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr {
return &ast.SelectorExpr{x, sel}
}
-
func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "TypeAssertion"))
@@ -1077,7 +1021,6 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
return &ast.TypeAssertExpr{x, typ}
}
-
func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "IndexOrSlice"))
@@ -1106,7 +1049,6 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
return &ast.IndexExpr{x, lbrack, low, rbrack}
}
-
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
if p.trace {
defer un(trace(p, "CallOrConversion"))
@@ -1133,7 +1075,6 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
}
-
func (p *parser) parseElement(keyOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "Element"))
@@ -1156,7 +1097,6 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
return x
}
-
func (p *parser) parseElementList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "ElementList"))
@@ -1173,7 +1113,6 @@ func (p *parser) parseElementList() (list []ast.Expr) {
return
}
-
func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "LiteralValue"))
@@ -1190,7 +1129,6 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
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) {
@@ -1227,7 +1165,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
return x
}
-
// isTypeName returns true iff x is a (qualified) TypeName.
func isTypeName(x ast.Expr) bool {
switch t := x.(type) {
@@ -1242,7 +1179,6 @@ func isTypeName(x ast.Expr) bool {
return true
}
-
// isLiteralType returns true iff x is a legal composite literal type.
func isLiteralType(x ast.Expr) bool {
switch t := x.(type) {
@@ -1260,7 +1196,6 @@ func isLiteralType(x ast.Expr) bool {
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 {
@@ -1269,7 +1204,6 @@ func deref(x ast.Expr) ast.Expr {
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 {
@@ -1278,7 +1212,6 @@ func unparen(x ast.Expr) ast.Expr {
return x
}
-
// checkExprOrType checks that x is an expression or a type
// (and not a raw type such as [...]T).
//
@@ -1303,7 +1236,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr {
if p.trace {
@@ -1358,7 +1290,6 @@ L:
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
if p.trace {
@@ -1396,7 +1327,6 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
return p.parsePrimaryExpr(lhs)
}
-
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
if p.trace {
@@ -1420,7 +1350,6 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
return x
}
-
// If lhs is set and the result is an identifier, it is not resolved.
// TODO(gri): parseExpr may return a type or even a raw type ([..]int) -
// should reject when a type/raw type is obviously not allowed
@@ -1432,12 +1361,10 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
return p.parseBinaryExpr(lhs, token.LowestPrec+1)
}
-
func (p *parser) parseRhs() ast.Expr {
return p.parseExpr(false)
}
-
// ----------------------------------------------------------------------------
// Statements
@@ -1500,7 +1427,6 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
return &ast.ExprStmt{x[0]}
}
-
func (p *parser) parseCallExpr() *ast.CallExpr {
x := p.parseRhs()
if call, isCall := x.(*ast.CallExpr); isCall {
@@ -1510,7 +1436,6 @@ func (p *parser) parseCallExpr() *ast.CallExpr {
return nil
}
-
func (p *parser) parseGoStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "GoStmt"))
@@ -1526,7 +1451,6 @@ func (p *parser) parseGoStmt() ast.Stmt {
return &ast.GoStmt{pos, call}
}
-
func (p *parser) parseDeferStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "DeferStmt"))
@@ -1542,7 +1466,6 @@ func (p *parser) parseDeferStmt() ast.Stmt {
return &ast.DeferStmt{pos, call}
}
-
func (p *parser) parseReturnStmt() *ast.ReturnStmt {
if p.trace {
defer un(trace(p, "ReturnStmt"))
@@ -1559,7 +1482,6 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
return &ast.ReturnStmt{pos, x}
}
-
func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
if p.trace {
defer un(trace(p, "BranchStmt"))
@@ -1578,7 +1500,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
return &ast.BranchStmt{pos, tok, label}
}
-
func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
if s == nil {
return nil
@@ -1590,7 +1511,6 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
return &ast.BadExpr{s.Pos(), s.End()}
}
-
func (p *parser) parseIfStmt() *ast.IfStmt {
if p.trace {
defer un(trace(p, "IfStmt"))
@@ -1633,7 +1553,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
return &ast.IfStmt{pos, s, x, body, else_}
}
-
func (p *parser) parseTypeList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "TypeList"))
@@ -1648,7 +1567,6 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
return
}
-
func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
if p.trace {
defer un(trace(p, "CaseClause"))
@@ -1675,7 +1593,6 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
return &ast.CaseClause{pos, list, colon, body}
}
-
func isExprSwitch(s ast.Stmt) bool {
if s == nil {
return true
@@ -1689,7 +1606,6 @@ func isExprSwitch(s ast.Stmt) bool {
return false
}
-
func (p *parser) parseSwitchStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "SwitchStmt"))
@@ -1735,7 +1651,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
return &ast.TypeSwitchStmt{pos, s1, s2, body}
}
-
func (p *parser) parseCommClause() *ast.CommClause {
if p.trace {
defer un(trace(p, "CommClause"))
@@ -1801,7 +1716,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
return &ast.CommClause{pos, comm, colon, body}
}
-
func (p *parser) parseSelectStmt() *ast.SelectStmt {
if p.trace {
defer un(trace(p, "SelectStmt"))
@@ -1820,7 +1734,6 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
return &ast.SelectStmt{pos, body}
}
-
func (p *parser) parseForStmt() ast.Stmt {
if p.trace {
defer un(trace(p, "ForStmt"))
@@ -1890,7 +1803,6 @@ func (p *parser) parseForStmt() ast.Stmt {
return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
}
-
func (p *parser) parseStmt() (s ast.Stmt) {
if p.trace {
defer un(trace(p, "Statement"))
@@ -1947,13 +1859,11 @@ func (p *parser) parseStmt() (s ast.Stmt) {
return
}
-
// ----------------------------------------------------------------------------
// Declarations
type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
-
func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "ImportSpec"))
@@ -1984,7 +1894,6 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
if p.trace {
defer un(trace(p, "ConstSpec"))
@@ -2009,7 +1918,6 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
return spec
}
-
func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "TypeSpec"))
@@ -2031,7 +1939,6 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "VarSpec"))
@@ -2056,7 +1963,6 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
return spec
}
-
func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
if p.trace {
defer un(trace(p, "GenDecl("+keyword.String()+")"))
@@ -2081,7 +1987,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
}
-
func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
if p.trace {
defer un(trace(p, "Receiver"))
@@ -2109,7 +2014,6 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
return par
}
-
func (p *parser) parseFuncDecl() *ast.FuncDecl {
if p.trace {
defer un(trace(p, "FunctionDecl"))
@@ -2150,7 +2054,6 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
return decl
}
-
func (p *parser) parseDecl() ast.Decl {
if p.trace {
defer un(trace(p, "Declaration"))
@@ -2181,7 +2084,6 @@ func (p *parser) parseDecl() ast.Decl {
return p.parseGenDecl(p.tok, f)
}
-
func (p *parser) parseDeclList() (list []ast.Decl) {
if p.trace {
defer un(trace(p, "DeclList"))
@@ -2194,7 +2096,6 @@ func (p *parser) parseDeclList() (list []ast.Decl) {
return
}
-
// ----------------------------------------------------------------------------
// Source files
diff --git a/libgo/go/go/printer/testdata/statements.golden b/libgo/go/go/printer/testdata/statements.golden
index 2900602699f..a6d85107f0b 100644
--- a/libgo/go/go/printer/testdata/statements.golden
+++ b/libgo/go/go/printer/testdata/statements.golden
@@ -30,7 +30,6 @@ func _() {
}
}
-
// Formatting of switch-statement headers.
func _() {
switch {
@@ -56,7 +55,6 @@ func _() {
}
}
-
// Formatting of switch statement bodies.
func _() {
switch {
@@ -110,6 +108,19 @@ func _() {
}
}
+// Formatting of selected select statements.
+func _() {
+ select {}
+ select { /* this comment should not be tab-aligned because the closing } is on the same line */
+ }
+ select { /* this comment should be tab-aligned */
+ }
+ select { // this comment should be tab-aligned
+ }
+ select {
+ case <-c:
+ }
+}
// Formatting of for-statement headers.
func _() {
@@ -149,7 +160,6 @@ func _() {
} // 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
@@ -243,7 +253,6 @@ func _() {
}
}
-
// Extra empty lines inside functions. Do respect source code line
// breaks between statement boundaries but print at most one empty
// line at a time.
@@ -276,19 +285,16 @@ func _() {
}
}
-
// Formatting around labels.
func _() {
L:
}
-
func _() {
// this comment should be indented
L: // no semicolon needed
}
-
func _() {
switch 0 {
case 0:
@@ -302,7 +308,6 @@ func _() {
}
}
-
func _() {
f()
L1:
@@ -312,26 +317,22 @@ L2:
L3:
}
-
func _() {
// this comment should be indented
L:
}
-
func _() {
L:
_ = 0
}
-
func _() {
// this comment should be indented
L:
_ = 0
}
-
func _() {
for {
L1:
@@ -341,7 +342,6 @@ func _() {
}
}
-
func _() {
// this comment should be indented
for {
@@ -352,7 +352,6 @@ func _() {
}
}
-
func _() {
if true {
_ = 0
@@ -370,7 +369,6 @@ L:
_ = 0
}
-
func _() {
for {
goto L
@@ -380,7 +378,6 @@ L:
MoreCode()
}
-
func _() {
for {
goto L
@@ -393,7 +390,6 @@ L: // A comment on the same line as the label, followed by a single empty line.
MoreCode()
}
-
func _() {
for {
goto L
@@ -404,7 +400,6 @@ L:
MoreCode()
}
-
func _() {
for {
goto AVeryLongLabelThatShouldNotAffectFormatting
diff --git a/libgo/go/go/printer/testdata/statements.input b/libgo/go/go/printer/testdata/statements.input
index 21e61efc4f8..86a753c5ad9 100644
--- a/libgo/go/go/printer/testdata/statements.input
+++ b/libgo/go/go/printer/testdata/statements.input
@@ -91,6 +91,19 @@ func _() {
}
+// Formatting of selected select statements.
+func _() {
+ select {
+ }
+ select { /* this comment should not be tab-aligned because the closing } is on the same line */ }
+ select { /* this comment should be tab-aligned */
+ }
+ select { // this comment should be tab-aligned
+ }
+ select { case <-c: }
+}
+
+
// Formatting of for-statement headers.
func _() {
for{}
diff --git a/libgo/go/go/scanner/errors.go b/libgo/go/go/scanner/errors.go
index 47e35a7107d..a0927e4167f 100644
--- a/libgo/go/go/scanner/errors.go
+++ b/libgo/go/go/scanner/errors.go
@@ -5,7 +5,6 @@
package scanner
import (
- "container/vector"
"fmt"
"go/token"
"io"
@@ -13,7 +12,6 @@ import (
"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
@@ -23,7 +21,6 @@ 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.
@@ -34,17 +31,14 @@ type ErrorHandler interface {
// error handling is obtained.
//
type ErrorVector struct {
- errors vector.Vector
+ errors []*Error
}
-
// Reset resets an ErrorVector to no errors.
-func (h *ErrorVector) Reset() { h.errors.Resize(0, 0) }
-
+func (h *ErrorVector) Reset() { h.errors = h.errors[:0] }
// ErrorCount returns the number of errors collected.
-func (h *ErrorVector) ErrorCount() int { return h.errors.Len() }
-
+func (h *ErrorVector) ErrorCount() int { return len(h.errors) }
// Within ErrorVector, an error is represented by an Error node. The
// position Pos, if valid, points to the beginning of the offending
@@ -55,7 +49,6 @@ type Error struct {
Msg string
}
-
func (e *Error) String() string {
if e.Pos.Filename != "" || e.Pos.IsValid() {
// don't print "<unknown position>"
@@ -65,16 +58,13 @@ func (e *Error) String() string {
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
@@ -95,7 +85,6 @@ func (p ErrorList) Less(i, j int) bool {
return false
}
-
func (p ErrorList) String() string {
switch len(p) {
case 0:
@@ -106,7 +95,6 @@ func (p ErrorList) String() 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.
//
@@ -116,20 +104,17 @@ const (
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 {
+ if len(h.errors) == 0 {
return nil
}
- list := make(ErrorList, h.errors.Len())
- for i := 0; i < h.errors.Len(); i++ {
- list[i] = h.errors.At(i).(*Error)
- }
+ list := make(ErrorList, len(h.errors))
+ copy(list, h.errors)
if mode >= Sorted {
sort.Sort(list)
@@ -151,26 +136,23 @@ func (h *ErrorVector) GetErrorList(mode int) ErrorList {
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 {
+ if len(h.errors) == 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})
+ h.errors = append(h.errors, &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.
diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go
index 07b7454c87d..7f3dd237328 100644
--- a/libgo/go/go/scanner/scanner.go
+++ b/libgo/go/go/scanner/scanner.go
@@ -22,6 +22,7 @@ package scanner
import (
"bytes"
+ "fmt"
"go/token"
"path/filepath"
"strconv"
@@ -29,7 +30,6 @@ import (
"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.
@@ -53,7 +53,6 @@ type Scanner struct {
ErrorCount int // number of errors encountered
}
-
// Read the next Unicode char into S.ch.
// S.ch < 0 means end-of-file.
//
@@ -87,7 +86,6 @@ func (S *Scanner) next() {
}
}
-
// The mode parameter to the Init function is a set of flags (or 0).
// They control scanner behavior.
//
@@ -133,37 +131,6 @@ func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint
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)
@@ -171,7 +138,6 @@ func (S *Scanner) error(offs int, msg string) {
S.ErrorCount++
}
-
var prefix = []byte("//line ")
func (S *Scanner) interpretLineComment(text []byte) {
@@ -192,7 +158,6 @@ func (S *Scanner) interpretLineComment(text []byte) {
}
}
-
func (S *Scanner) scanComment() {
// initial '/' already consumed; S.ch == '/' || S.ch == '*'
offs := S.offset - 1 // position of initial '/'
@@ -224,7 +189,6 @@ func (S *Scanner) scanComment() {
S.error(offs, "comment not terminated")
}
-
func (S *Scanner) findLineEnd() bool {
// initial '/' already consumed
@@ -269,17 +233,14 @@ func (S *Scanner) findLineEnd() bool {
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) {
@@ -288,7 +249,6 @@ func (S *Scanner) scanIdentifier() token.Token {
return token.Lookup(S.src[offs:S.offset])
}
-
func digitVal(ch int) int {
switch {
case '0' <= ch && ch <= '9':
@@ -301,14 +261,12 @@ func digitVal(ch int) int {
return 16 // larger than any legal digit val
}
-
func (S *Scanner) scanMantissa(base int) {
for digitVal(S.ch) < base {
S.next()
}
}
-
func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
// digitVal(S.ch) < 10
tok := token.INT
@@ -327,6 +285,10 @@ func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
// hexadecimal int
S.next()
S.scanMantissa(16)
+ if S.offset-offs <= 2 {
+ // only scanned "0x" or "0X"
+ S.error(offs, "illegal hexadecimal number")
+ }
} else {
// octal int or float
seenDecimalDigit := false
@@ -376,7 +338,6 @@ exit:
return tok
}
-
func (S *Scanner) scanEscape(quote int) {
offs := S.offset
@@ -421,7 +382,6 @@ func (S *Scanner) scanEscape(quote int) {
}
}
-
func (S *Scanner) scanChar() {
// '\'' opening already consumed
offs := S.offset - 1
@@ -448,7 +408,6 @@ func (S *Scanner) scanChar() {
}
}
-
func (S *Scanner) scanString() {
// '"' opening already consumed
offs := S.offset - 1
@@ -468,7 +427,6 @@ func (S *Scanner) scanString() {
S.next()
}
-
func (S *Scanner) scanRawString() {
// '`' opening already consumed
offs := S.offset - 1
@@ -485,14 +443,12 @@ func (S *Scanner) scanRawString() {
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
@@ -507,7 +463,6 @@ func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token {
return tok0
}
-
func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) token.Token {
if S.ch == '=' {
S.next()
@@ -520,7 +475,6 @@ func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) tok
return tok0
}
-
func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Token) token.Token {
if S.ch == '=' {
S.next()
@@ -537,7 +491,6 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke
return tok0
}
-
// Scan scans the next token and returns the token position,
// the token, and the literal string corresponding to the
// token. The source end is indicated by token.EOF.
@@ -700,7 +653,7 @@ scanAgain:
tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
default:
if S.mode&AllowIllegalChars == 0 {
- S.error(offs, "illegal character "+charString(ch))
+ S.error(offs, fmt.Sprintf("illegal character %#U", ch))
}
insertSemi = S.insertSemi // preserve insertSemi info
}
diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go
index 8afb00ee5bc..eb9e1cb818a 100644
--- a/libgo/go/go/scanner/scanner_test.go
+++ b/libgo/go/go/scanner/scanner_test.go
@@ -12,10 +12,8 @@ import (
"testing"
)
-
var fset = token.NewFileSet()
-
const /* class */ (
special = iota
literal
@@ -23,7 +21,6 @@ const /* class */ (
keyword
)
-
func tokenclass(tok token.Token) int {
switch {
case tok.IsLiteral():
@@ -36,14 +33,12 @@ func tokenclass(tok token.Token) int {
return special
}
-
type elt struct {
tok token.Token
lit string
class int
}
-
var tokens = [...]elt{
// Special tokens
{token.COMMENT, "/* a comment */", special},
@@ -89,7 +84,7 @@ var tokens = [...]elt{
literal,
},
- // Operators and delimitors
+ // Operators and delimiters
{token.ADD, "+", operator},
{token.SUB, "-", operator},
{token.MUL, "*", operator},
@@ -178,7 +173,6 @@ var tokens = [...]elt{
{token.VAR, "var", keyword},
}
-
const whitespace = " \t \n\n\n" // to separate tokens
type testErrorHandler struct {
@@ -189,7 +183,6 @@ 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++ {
@@ -200,7 +193,6 @@ func newlineCount(s string) int {
return n
}
-
func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
pos := fset.Position(p)
if pos.Filename != expected.Filename {
@@ -217,7 +209,6 @@ func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
}
}
-
// Verify that calling Scan() provides the correct results.
func TestScan(t *testing.T) {
// make source
@@ -271,7 +262,6 @@ func TestScan(t *testing.T) {
}
}
-
func checkSemi(t *testing.T, line string, mode uint) {
var S Scanner
file := fset.AddFile("TestSemis", fset.Base(), len(line))
@@ -305,7 +295,6 @@ func checkSemi(t *testing.T, line string, mode uint) {
}
}
-
var lines = []string{
// # indicates a semicolon present in the source
// $ indicates an automatically inserted semicolon
@@ -429,7 +418,6 @@ var lines = []string{
"package main$",
}
-
func TestSemis(t *testing.T) {
for _, line := range lines {
checkSemi(t, line, AllowIllegalChars|InsertSemis)
@@ -463,25 +451,31 @@ var segments = []segment{
{"\n //line foo:42\n line44", filepath.Join("dir", "foo"), 44}, // bad line comment, ignored
{"\n//line foo 42\n line46", filepath.Join("dir", "foo"), 46}, // bad line comment, ignored
{"\n//line foo:42 extra text\n line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored
- {"\n//line /bar:42\n line42", string(filepath.Separator) + "bar", 42},
{"\n//line ./foo:42\n line42", filepath.Join("dir", "foo"), 42},
{"\n//line a/b/c/File1.go:100\n line100", filepath.Join("dir", "a", "b", "c", "File1.go"), 100},
}
+var unixsegments = []segment{
+ {"\n//line /bar:42\n line42", "/bar", 42},
+}
+
var winsegments = []segment{
+ {"\n//line c:\\bar:42\n line42", "c:\\bar", 42},
{"\n//line c:\\dir\\File1.go:100\n line100", "c:\\dir\\File1.go", 100},
}
-
// Verify that comments of the form "//line filename:line" are interpreted correctly.
func TestLineComments(t *testing.T) {
+ segs := segments
if runtime.GOOS == "windows" {
- segments = append(segments, winsegments...)
+ segs = append(segs, winsegments...)
+ } else {
+ segs = append(segs, unixsegments...)
}
// make source
var src string
- for _, e := range segments {
+ for _, e := range segs {
src += e.srcline
}
@@ -489,7 +483,7 @@ func TestLineComments(t *testing.T) {
var S Scanner
file := fset.AddFile(filepath.Join("dir", "TestLineComments"), fset.Base(), len(src))
S.Init(file, []byte(src), nil, 0)
- for _, s := range segments {
+ for _, s := range segs {
p, _, lit := S.Scan()
pos := file.Position(p)
checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
@@ -500,7 +494,6 @@ func TestLineComments(t *testing.T) {
}
}
-
// Verify that initializing the same scanner more then once works correctly.
func TestInit(t *testing.T) {
var s Scanner
@@ -536,7 +529,6 @@ func TestInit(t *testing.T) {
}
}
-
func TestIllegalChars(t *testing.T) {
var s Scanner
@@ -558,7 +550,6 @@ func TestIllegalChars(t *testing.T) {
}
}
-
func TestStdErrorHander(t *testing.T) {
const src = "@\n" + // illegal character, cause an error
"@ @\n" + // two errors on the same line
@@ -601,21 +592,18 @@ func TestStdErrorHander(t *testing.T) {
}
}
-
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
@@ -643,14 +631,15 @@ func checkError(t *testing.T, src string, tok token.Token, pos int, err string)
}
}
-
var errors = []struct {
src string
tok token.Token
pos int
err string
}{
- {`#`, token.ILLEGAL, 0, "illegal character '#' (U+23)"},
+ {"\a", token.ILLEGAL, 0, "illegal character U+0007"},
+ {`#`, token.ILLEGAL, 0, "illegal character U+0023 '#'"},
+ {`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"},
{`' '`, token.CHAR, 0, ""},
{`''`, token.CHAR, 0, "illegal character literal"},
{`'\8'`, token.CHAR, 2, "unknown escape sequence"},
@@ -670,11 +659,12 @@ var errors = []struct {
{"078e0", token.FLOAT, 0, ""},
{"078", token.INT, 0, "illegal octal number"},
{"07800000009", token.INT, 0, "illegal octal number"},
+ {"0x", token.INT, 0, "illegal hexadecimal number"},
+ {"0X", token.INT, 0, "illegal hexadecimal 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
index 8c35eeb52f7..c559e19f886 100644
--- a/libgo/go/go/token/position.go
+++ b/libgo/go/go/token/position.go
@@ -12,7 +12,6 @@ import (
"sync"
)
-
// Position describes an arbitrary source position
// including the file, line, and column location.
// A Position is valid if the line number is > 0.
@@ -24,11 +23,9 @@ type Position struct {
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
@@ -50,7 +47,6 @@ func (pos Position) String() string {
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.
@@ -73,7 +69,6 @@ func (pos Position) String() string {
//
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
@@ -81,18 +76,15 @@ type Pos int
//
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 f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size {
return f
@@ -108,7 +100,6 @@ func (s *FileSet) file(p Pos) *File {
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.
@@ -122,7 +113,6 @@ func (s *FileSet) File(p Pos) (f *File) {
return
}
-
func (f *File) position(p Pos) (pos Position) {
offset := int(p) - f.base
pos.Offset = offset
@@ -130,12 +120,11 @@ func (f *File) position(p Pos) (pos Position) {
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
+ // is in the last file added, or perhaps
// looked at - will eliminate one level
// of search
s.mutex.RLock()
@@ -147,14 +136,12 @@ func (s *FileSet) Position(p Pos) (pos Position) {
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 smaller than the
@@ -171,7 +158,6 @@ func (f *File) AddLineInfo(offset int, filename string, line int) {
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.
//
@@ -186,25 +172,21 @@ type File struct {
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()
@@ -213,7 +195,6 @@ func (f *File) LineCount() int {
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 smaller than the file size; otherwise the line offset is ignored.
@@ -226,7 +207,6 @@ func (f *File) AddLine(offset int) {
f.set.mutex.Unlock()
}
-
// SetLines sets the line offsets for a file and returns true if successful.
// The line offsets are the offsets of the first character of each line;
// for instance for the content "ab\nc\n" the line offsets are {0, 3}.
@@ -251,7 +231,6 @@ func (f *File) SetLines(lines []int) bool {
return true
}
-
// SetLinesForContent sets the line offsets for the given file content.
func (f *File) SetLinesForContent(content []byte) {
var lines []int
@@ -272,7 +251,6 @@ func (f *File) SetLinesForContent(content []byte) {
f.set.mutex.Unlock()
}
-
// Pos returns the Pos value for the given file offset;
// the offset must be <= f.Size().
// f.Pos(f.Offset(p)) == p.
@@ -284,7 +262,6 @@ func (f *File) Pos(offset int) Pos {
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.
@@ -296,7 +273,6 @@ func (f *File) Offset(p Pos) int {
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.
//
@@ -305,7 +281,6 @@ func (f *File) Line(p Pos) int {
return f.Position(p).Line
}
-
// Position returns the Position value for the given file position p;
// p must be a Pos value in that file or NoPos.
//
@@ -319,7 +294,6 @@ func (f *File) Position(p Pos) (pos Position) {
return
}
-
func searchInts(a []int, x int) int {
// This function body is a manually inlined version of:
//
@@ -342,12 +316,10 @@ func searchInts(a []int, x int) int {
return i - 1
}
-
func searchLineInfos(a []lineInfo, x int) int {
return sort.Search(len(a), func(i int) bool { return a[i].offset > x }) - 1
}
-
// 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
@@ -367,7 +339,6 @@ func (f *File) info(offset int) (filename string, line, column int) {
return
}
-
// A FileSet represents a set of source files.
// Methods of file sets are synchronized; multiple goroutines
// may invoke them concurrently.
@@ -379,7 +350,6 @@ type FileSet struct {
last *File // cache of last file looked up
}
-
// NewFileSet creates a new file set.
func NewFileSet() *FileSet {
s := new(FileSet)
@@ -387,7 +357,6 @@ func NewFileSet() *FileSet {
return s
}
-
// Base returns the minimum base offset that must be provided to
// AddFile when adding the next file.
//
@@ -399,7 +368,6 @@ func (s *FileSet) Base() int {
}
-
// 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
@@ -434,7 +402,6 @@ func (s *FileSet) AddFile(filename string, base, size int) *File {
return f
}
-
// Files returns the files added to the file set.
func (s *FileSet) Files() <-chan *File {
ch := make(chan *File)
diff --git a/libgo/go/go/token/position_test.go b/libgo/go/go/token/position_test.go
index 979c9b1e8e7..30bec59913a 100644
--- a/libgo/go/go/token/position_test.go
+++ b/libgo/go/go/token/position_test.go
@@ -9,7 +9,6 @@ import (
"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)
@@ -25,7 +24,6 @@ func checkPos(t *testing.T, msg string, p, q Position) {
}
}
-
func TestNoPos(t *testing.T) {
if NoPos.IsValid() {
t.Errorf("NoPos should not be valid")
@@ -36,7 +34,6 @@ func TestNoPos(t *testing.T) {
checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
}
-
var tests = []struct {
filename string
source []byte // may be nil
@@ -53,7 +50,6 @@ var tests = []struct {
{"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}},
}
-
func linecol(lines []int, offs int) (int, int) {
prevLineOffs := 0
for line, lineOffs := range lines {
@@ -65,7 +61,6 @@ func linecol(lines []int, offs int) (int, int) {
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)
@@ -80,7 +75,6 @@ func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
}
}
-
func makeTestSource(size int, lines []int) []byte {
src := make([]byte, size)
for _, offs := range lines {
@@ -91,7 +85,6 @@ func makeTestSource(size int, lines []int) []byte {
return src
}
-
func TestPositions(t *testing.T) {
const delta = 7 // a non-zero base offset increment
fset := NewFileSet()
@@ -150,7 +143,6 @@ func TestPositions(t *testing.T) {
}
}
-
func TestLineInfo(t *testing.T) {
fset := NewFileSet()
f := fset.AddFile("foo", fset.Base(), 500)
@@ -170,7 +162,6 @@ func TestLineInfo(t *testing.T) {
}
}
-
func TestFiles(t *testing.T) {
fset := NewFileSet()
for i, test := range tests {
diff --git a/libgo/go/go/token/token.go b/libgo/go/go/token/token.go
index c2ec80ae140..557374052c9 100644
--- a/libgo/go/go/token/token.go
+++ b/libgo/go/go/token/token.go
@@ -9,7 +9,6 @@ package token
import "strconv"
-
// Token is the set of lexical tokens of the Go programming language.
type Token int
@@ -124,7 +123,6 @@ const (
keyword_end
)
-
var tokens = [...]string{
ILLEGAL: "ILLEGAL",
@@ -225,7 +223,6 @@ var tokens = [...]string{
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
@@ -243,7 +240,6 @@ func (tok Token) String() string {
return s
}
-
// 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
@@ -256,7 +252,6 @@ const (
HighestPrec = 7
)
-
// Precedence returns the operator precedence of the binary
// operator op. If op is not a binary operator, the result
// is LowestPrecedence.
@@ -277,7 +272,6 @@ func (op Token) Precedence() int {
return LowestPrec
}
-
var keywords map[string]Token
func init() {
@@ -287,7 +281,6 @@ func init() {
}
}
-
// Lookup maps an identifier to its keyword token or IDENT (if not a keyword).
//
func Lookup(ident []byte) Token {
@@ -299,7 +292,6 @@ func Lookup(ident []byte) Token {
return IDENT
}
-
// Predicates
// IsLiteral returns true for tokens corresponding to identifiers
diff --git a/libgo/go/go/typechecker/scope.go b/libgo/go/go/typechecker/scope.go
index a4bee6e6962..d73d1a45048 100644
--- a/libgo/go/go/typechecker/scope.go
+++ b/libgo/go/go/typechecker/scope.go
@@ -12,18 +12,15 @@ package typechecker
import "go/ast"
-
func (tc *typechecker) openScope() *ast.Scope {
tc.topScope = ast.NewScope(tc.topScope)
return tc.topScope
}
-
func (tc *typechecker) closeScope() {
tc.topScope = tc.topScope.Outer
}
-
// 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.
@@ -40,13 +37,11 @@ func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast
return obj
}
-
// decl is the same as declInScope(tc.topScope, ...)
func (tc *typechecker) decl(kind ast.ObjKind, 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) {
@@ -61,7 +56,6 @@ func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
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 *Type, name *ast.Ident) (obj *ast.Object) {
diff --git a/libgo/go/go/typechecker/type.go b/libgo/go/go/typechecker/type.go
index 62b4e9d3e4a..1b88eb54b85 100644
--- a/libgo/go/go/typechecker/type.go
+++ b/libgo/go/go/typechecker/type.go
@@ -6,7 +6,6 @@ package typechecker
import "go/ast"
-
// A Type represents a Go type.
type Type struct {
Form Form
@@ -18,13 +17,11 @@ type Type struct {
Expr ast.Expr // corresponding AST expression
}
-
// NewType creates a new type of a given form.
func NewType(form Form) *Type {
return &Type{Form: form, Scope: ast.NewScope(nil)}
}
-
// Form describes the form of a type.
type Form int
@@ -45,7 +42,6 @@ const (
Tuple
)
-
var formStrings = [...]string{
BadType: "badType",
Unresolved: "unresolved",
@@ -62,10 +58,8 @@ var formStrings = [...]string{
Tuple: "tuple",
}
-
func (form Form) String() string { return formStrings[form] }
-
// The list of basic type id's.
const (
Bool = iota
@@ -96,7 +90,6 @@ const (
// TODO(gri) ideal types are missing
)
-
var BasicTypes = map[uint]string{
Bool: "bool",
Byte: "byte",
diff --git a/libgo/go/go/typechecker/typechecker.go b/libgo/go/go/typechecker/typechecker.go
index b151f5834da..24480165bde 100644
--- a/libgo/go/go/typechecker/typechecker.go
+++ b/libgo/go/go/typechecker/typechecker.go
@@ -17,19 +17,16 @@ import (
"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
@@ -46,7 +43,6 @@ func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.E
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.
@@ -57,7 +53,6 @@ func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error
return CheckPackage(fset, pkg, importer)
}
-
// ----------------------------------------------------------------------------
// Typechecker state
@@ -71,19 +66,16 @@ type typechecker struct {
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:
@@ -158,7 +150,6 @@ func (tc *typechecker) checkPackage(pkg *ast.Package) {
pkg.Scope = tc.topScope
}
-
func (tc *typechecker) declGlobal(global ast.Decl) {
switch d := global.(type) {
case *ast.BadDecl:
@@ -218,7 +209,6 @@ func (tc *typechecker) declGlobal(global ast.Decl) {
}
}
-
// 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 {
@@ -227,7 +217,6 @@ func deref(x ast.Expr) ast.Expr {
return x
}
-
func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
// a method is declared in the receiver base type's scope
var scope *ast.Scope
@@ -259,7 +248,6 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
tc.declInScope(scope, ast.Fun, method.Name, method, 0)
}
-
func (tc *typechecker) resolve(obj *ast.Object) {
// check for declaration cycles
if tc.cyclemap[obj] {
@@ -318,7 +306,6 @@ func (tc *typechecker) resolve(obj *ast.Object) {
}
}
-
func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
tc.openScope()
defer tc.closeScope()
@@ -338,7 +325,6 @@ func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) {
}
}
-
// ----------------------------------------------------------------------------
// Types
@@ -350,7 +336,6 @@ func unparen(x ast.Expr) ast.Expr {
return x
}
-
func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) {
if fields != nil {
for _, f := range fields.List {
@@ -365,7 +350,6 @@ func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref b
return n
}
-
func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.FieldList) {
assert((typ.Form == Method) == (recv != nil))
typ.Params = ast.NewScope(nil)
@@ -374,7 +358,6 @@ func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.Field
typ.N = tc.declFields(typ.Params, results, true)
}
-
func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
x = unparen(x)
@@ -472,17 +455,14 @@ func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) {
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
index d16e0692180..4bad4499a47 100644
--- a/libgo/go/go/typechecker/typechecker_test.go
+++ b/libgo/go/go/typechecker/typechecker_test.go
@@ -41,7 +41,6 @@ import (
"testing"
)
-
const testDir = "./testdata" // location of test packages
var fset = token.NewFileSet()
@@ -51,7 +50,6 @@ var (
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 *"([^"]*)" *\*/$`)
@@ -91,12 +89,10 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) {
return
}
-
func testFilter(f *os.FileInfo) bool {
return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.'
}
-
func checkError(t *testing.T, expected, found *scanner.Error) {
rx, err := regexp.Compile(expected.Msg)
if err != nil {
@@ -120,7 +116,6 @@ func checkError(t *testing.T, expected, found *scanner.Error) {
}
}
-
func TestTypeCheck(t *testing.T) {
flag.Parse()
pkgRx, err := regexp.Compile(*pkgPat)
diff --git a/libgo/go/go/typechecker/universe.go b/libgo/go/go/typechecker/universe.go
index abc8bbbd49c..81c14a05e57 100644
--- a/libgo/go/go/typechecker/universe.go
+++ b/libgo/go/go/typechecker/universe.go
@@ -11,7 +11,6 @@ import "go/ast"
// The Universe scope contains all predeclared identifiers.
var Universe *ast.Scope
-
func def(obj *ast.Object) {
alt := Universe.Insert(obj)
if alt != nil {
@@ -19,7 +18,6 @@ func def(obj *ast.Object) {
}
}
-
func init() {
Universe = ast.NewScope(nil)
diff --git a/libgo/go/go/types/check.go b/libgo/go/go/types/check.go
new file mode 100644
index 00000000000..87e3e93da73
--- /dev/null
+++ b/libgo/go/go/types/check.go
@@ -0,0 +1,226 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the Check function, which typechecks a package.
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/scanner"
+ "go/token"
+ "os"
+ "strconv"
+)
+
+const debug = false
+
+type checker struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ types map[ast.Expr]Type
+}
+
+func (c *checker) errorf(pos token.Pos, format string, args ...interface{}) string {
+ msg := fmt.Sprintf(format, args...)
+ c.Error(c.fset.Position(pos), msg)
+ return msg
+}
+
+// collectFields collects struct fields tok = token.STRUCT), interface methods
+// (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC).
+func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) {
+ if list != nil {
+ for _, field := range list.List {
+ ftype := field.Type
+ if t, ok := ftype.(*ast.Ellipsis); ok {
+ ftype = t.Elt
+ isVariadic = true
+ }
+ typ := c.makeType(ftype, cycleOk)
+ tag := ""
+ if field.Tag != nil {
+ assert(field.Tag.Kind == token.STRING)
+ tag, _ = strconv.Unquote(field.Tag.Value)
+ }
+ if len(field.Names) > 0 {
+ // named fields
+ for _, name := range field.Names {
+ obj := name.Obj
+ obj.Type = typ
+ fields = append(fields, obj)
+ if tok == token.STRUCT {
+ tags = append(tags, tag)
+ }
+ }
+ } else {
+ // anonymous field
+ switch tok {
+ case token.STRUCT:
+ tags = append(tags, tag)
+ fallthrough
+ case token.FUNC:
+ obj := ast.NewObj(ast.Var, "")
+ obj.Type = typ
+ fields = append(fields, obj)
+ case token.INTERFACE:
+ utyp := Underlying(typ)
+ if typ, ok := utyp.(*Interface); ok {
+ // TODO(gri) This is not good enough. Check for double declarations!
+ fields = append(fields, typ.Methods...)
+ } else if _, ok := utyp.(*Bad); !ok {
+ // if utyp is Bad, don't complain (the root cause was reported before)
+ c.errorf(ftype.Pos(), "interface contains embedded non-interface type")
+ }
+ default:
+ panic("unreachable")
+ }
+ }
+ }
+ }
+ return
+}
+
+// makeType makes a new type for an AST type specification x or returns
+// the type referred to by a type name x. If cycleOk is set, a type may
+// refer to itself directly or indirectly; otherwise cycles are errors.
+//
+func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) {
+ if debug {
+ fmt.Printf("makeType (cycleOk = %v)\n", cycleOk)
+ ast.Print(c.fset, x)
+ defer func() {
+ fmt.Printf("-> %T %v\n\n", typ, typ)
+ }()
+ }
+
+ switch t := x.(type) {
+ case *ast.BadExpr:
+ return &Bad{}
+
+ case *ast.Ident:
+ // type name
+ obj := t.Obj
+ if obj == nil {
+ // unresolved identifier (error has been reported before)
+ return &Bad{Msg: "unresolved identifier"}
+ }
+ if obj.Kind != ast.Typ {
+ msg := c.errorf(t.Pos(), "%s is not a type", t.Name)
+ return &Bad{Msg: msg}
+ }
+ c.checkObj(obj, cycleOk)
+ if !cycleOk && obj.Type.(*Name).Underlying == nil {
+ // TODO(gri) Enable this message again once its position
+ // is independent of the underlying map implementation.
+ // msg := c.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
+ msg := "illegal cycle"
+ return &Bad{Msg: msg}
+ }
+ return obj.Type.(Type)
+
+ case *ast.ParenExpr:
+ return c.makeType(t.X, cycleOk)
+
+ case *ast.SelectorExpr:
+ // qualified identifier
+ // TODO (gri) eventually, this code belongs to expression
+ // type checking - here for the time being
+ if ident, ok := t.X.(*ast.Ident); ok {
+ if obj := ident.Obj; obj != nil {
+ if obj.Kind != ast.Pkg {
+ msg := c.errorf(ident.Pos(), "%s is not a package", obj.Name)
+ return &Bad{Msg: msg}
+ }
+ // TODO(gri) we have a package name but don't
+ // have the mapping from package name to package
+ // scope anymore (created in ast.NewPackage).
+ return &Bad{} // for now
+ }
+ }
+ // TODO(gri) can this really happen (the parser should have excluded this)?
+ msg := c.errorf(t.Pos(), "expected qualified identifier")
+ return &Bad{Msg: msg}
+
+ case *ast.StarExpr:
+ return &Pointer{Base: c.makeType(t.X, true)}
+
+ case *ast.ArrayType:
+ if t.Len != nil {
+ // TODO(gri) compute length
+ return &Array{Elt: c.makeType(t.Elt, cycleOk)}
+ }
+ return &Slice{Elt: c.makeType(t.Elt, true)}
+
+ case *ast.StructType:
+ fields, tags, _ := c.collectFields(token.STRUCT, t.Fields, cycleOk)
+ return &Struct{Fields: fields, Tags: tags}
+
+ case *ast.FuncType:
+ params, _, _ := c.collectFields(token.FUNC, t.Params, true)
+ results, _, isVariadic := c.collectFields(token.FUNC, t.Results, true)
+ return &Func{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic}
+
+ case *ast.InterfaceType:
+ methods, _, _ := c.collectFields(token.INTERFACE, t.Methods, cycleOk)
+ methods.Sort()
+ return &Interface{Methods: methods}
+
+ case *ast.MapType:
+ return &Map{Key: c.makeType(t.Key, true), Elt: c.makeType(t.Key, true)}
+
+ case *ast.ChanType:
+ return &Chan{Dir: t.Dir, Elt: c.makeType(t.Value, true)}
+ }
+
+ panic(fmt.Sprintf("unreachable (%T)", x))
+}
+
+// checkObj type checks an object.
+func (c *checker) checkObj(obj *ast.Object, ref bool) {
+ if obj.Type != nil {
+ // object has already been type checked
+ return
+ }
+
+ switch obj.Kind {
+ case ast.Bad:
+ // ignore
+
+ case ast.Con:
+ // TODO(gri) complete this
+
+ case ast.Typ:
+ typ := &Name{Obj: obj}
+ obj.Type = typ // "mark" object so recursion terminates
+ typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
+
+ case ast.Var:
+ // TODO(gri) complete this
+
+ case ast.Fun:
+ // TODO(gri) complete this
+
+ default:
+ panic("unreachable")
+ }
+}
+
+// Check typechecks a package.
+// It augments the AST by assigning types to all ast.Objects and returns a map
+// of types for all expression nodes in statements, and a scanner.ErrorList if
+// there are errors.
+//
+func Check(fset *token.FileSet, pkg *ast.Package) (types map[ast.Expr]Type, err os.Error) {
+ var c checker
+ c.fset = fset
+ c.types = make(map[ast.Expr]Type)
+
+ for _, obj := range pkg.Scope.Objects {
+ c.checkObj(obj, false)
+ }
+
+ return c.types, c.GetError(scanner.NoMultiples)
+}
diff --git a/libgo/go/go/types/check_test.go b/libgo/go/go/types/check_test.go
new file mode 100644
index 00000000000..8be653fcb66
--- /dev/null
+++ b/libgo/go/go/types/check_test.go
@@ -0,0 +1,215 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements a typechecker test harness. The packages specified
+// in tests are typechecked. Error messages reported by the typechecker are
+// compared against the error messages expected in 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 p
+// func f() {
+// _ = x /* ERROR "not declared" */ + 1
+// }
+
+package types
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/scanner"
+ "go/token"
+ "io/ioutil"
+ "os"
+ "regexp"
+ "testing"
+)
+
+// The test filenames do not end in .go so that they are invisible
+// to gofmt since they contain comments that must not change their
+// positions relative to surrounding tokens.
+
+var tests = []struct {
+ name string
+ files []string
+}{
+ {"test0", []string{"testdata/test0.src"}},
+}
+
+var fset = token.NewFileSet()
+
+// TODO(gri) This functionality should be in token.Fileset.
+func getFile(filename string) *token.File {
+ for f := range fset.Files() {
+ if f.Name() == filename {
+ return f
+ }
+ }
+ return nil
+}
+
+// TODO(gri) This functionality should be in token.Fileset.
+func getPos(filename string, offset int) token.Pos {
+ if f := getFile(filename); f != nil {
+ return f.Pos(offset)
+ }
+ return token.NoPos
+}
+
+// TODO(gri) Need to revisit parser interface. We should be able to use parser.ParseFiles
+// or a similar function instead.
+func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*ast.File, os.Error) {
+ files := make(map[string]*ast.File)
+ var errors scanner.ErrorList
+ for _, filename := range filenames {
+ if _, exists := files[filename]; exists {
+ t.Fatalf("%s: duplicate file %s", testname, filename)
+ }
+ file, err := parser.ParseFile(fset, filename, nil, parser.DeclarationErrors)
+ if file == nil {
+ t.Fatalf("%s: could not parse file %s", testname, filename)
+ }
+ files[filename] = file
+ if err != nil {
+ // if the parser returns a non-scanner.ErrorList error
+ // the file couldn't be read in the first place and
+ // file == nil; in that case we shouldn't reach here
+ errors = append(errors, err.(scanner.ErrorList)...)
+ }
+
+ }
+ return files, errors
+}
+
+// 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 files and returns them as a map of error positions to error messages.
+//
+func expectedErrors(t *testing.T, testname string, files map[string]*ast.File) map[token.Pos]string {
+ errors := make(map[token.Pos]string)
+ for filename := range files {
+ src, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Fatalf("%s: could not read %s", testname, filename)
+ }
+
+ var s scanner.Scanner
+ // file was parsed already - do not add it again to the file
+ // set otherwise the position information returned here will
+ // not match the position information collected by the parser
+ s.Init(getFile(filename), src, nil, scanner.ScanComments)
+ var prev token.Pos // position of last non-comment token
+
+ scanFile:
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ break scanFile
+ case token.COMMENT:
+ s := errRx.FindStringSubmatch(lit)
+ if len(s) == 2 {
+ errors[prev] = string(s[1])
+ }
+ default:
+ prev = pos
+ }
+ }
+ }
+ return errors
+}
+
+func eliminate(t *testing.T, expected map[token.Pos]string, errors os.Error) {
+ if errors == nil {
+ return
+ }
+ for _, error := range errors.(scanner.ErrorList) {
+ // error.Pos is a token.Position, but we want
+ // a token.Pos so we can do a map lookup
+ // TODO(gri) Need to move scanner.Errors over
+ // to use token.Pos and file set info.
+ pos := getPos(error.Pos.Filename, error.Pos.Offset)
+ if msg, found := expected[pos]; found {
+ // we expect a message at pos; check if it matches
+ rx, err := regexp.Compile(msg)
+ if err != nil {
+ t.Errorf("%s: %v", error.Pos, err)
+ continue
+ }
+ if match := rx.MatchString(error.Msg); !match {
+ t.Errorf("%s: %q does not match %q", error.Pos, error.Msg, msg)
+ continue
+ }
+ // we have a match - eliminate this error
+ expected[pos] = "", false
+ } else {
+ // To keep in mind when analyzing failed test output:
+ // If the same error position occurs multiple times in errors,
+ // this message will be triggered (because the first error at
+ // the position removes this position from the expected errors).
+ t.Errorf("%s: no (multiple?) error expected, but found: %s", error.Pos, error.Msg)
+ }
+ }
+}
+
+func check(t *testing.T, testname string, testfiles []string) {
+ // TODO(gri) Eventually all these different phases should be
+ // subsumed into a single function call that takes
+ // a set of files and creates a fully resolved and
+ // type-checked AST.
+
+ files, err := parseFiles(t, testname, testfiles)
+
+ // we are expecting the following errors
+ // (collect these after parsing the files so that
+ // they are found in the file set)
+ errors := expectedErrors(t, testname, files)
+
+ // verify errors returned by the parser
+ eliminate(t, errors, err)
+
+ // verify errors returned after resolving identifiers
+ pkg, err := ast.NewPackage(fset, files, GcImporter, Universe)
+ eliminate(t, errors, err)
+
+ // verify errors returned by the typechecker
+ _, err = Check(fset, pkg)
+ eliminate(t, errors, err)
+
+ // there should be no expected errors left
+ if len(errors) > 0 {
+ t.Errorf("%s: %d errors not reported:", testname, len(errors))
+ for pos, msg := range errors {
+ t.Errorf("%s: %s\n", fset.Position(pos), msg)
+ }
+ }
+}
+
+func TestCheck(t *testing.T) {
+ // For easy debugging w/o changing the testing code,
+ // if there is a local test file, only test that file.
+ const testfile = "test.go"
+ if fi, err := os.Stat(testfile); err == nil && fi.IsRegular() {
+ fmt.Printf("WARNING: Testing only %s (remove it to run all tests)\n", testfile)
+ check(t, testfile, []string{testfile})
+ return
+ }
+
+ // Otherwise, run all the tests.
+ for _, test := range tests {
+ check(t, test.name, test.files)
+ }
+}
diff --git a/libgo/go/go/types/const.go b/libgo/go/go/types/const.go
index 6fdc22f6b34..1ef95d9f952 100644
--- a/libgo/go/go/types/const.go
+++ b/libgo/go/go/types/const.go
@@ -12,7 +12,6 @@ import (
"strconv"
)
-
// TODO(gri) Consider changing the API so Const is an interface
// and operations on consts don't have to type switch.
@@ -28,20 +27,17 @@ type Const struct {
val interface{}
}
-
// Representation of complex values.
type cmplx struct {
re, im *big.Rat
}
-
func assert(cond bool) {
if !cond {
panic("go/types internal error: assertion failed")
}
}
-
// MakeConst makes an ideal constant from a literal
// token and the corresponding literal string.
func MakeConst(tok token.Token, lit string) Const {
@@ -75,14 +71,12 @@ func MakeConst(tok token.Token, lit string) Const {
panic("unreachable")
}
-
// MakeZero returns the zero constant for the given type.
func MakeZero(typ *Type) Const {
// TODO(gri) fix this
return Const{0}
}
-
// Match attempts to match the internal constant representations of x and y.
// If the attempt is successful, the result is the values of x and y,
// if necessary converted to have the same internal representation; otherwise
@@ -132,7 +126,6 @@ func (x Const) Match(y Const) (u, v Const) {
return
}
-
// Convert attempts to convert the constant x to a given type.
// If the attempt is successful, the result is the new constant;
// otherwise the result is invalid.
@@ -148,7 +141,6 @@ func (x Const) Convert(typ *Type) Const {
return x
}
-
func (x Const) String() string {
switch x := x.val.(type) {
case bool:
@@ -169,12 +161,10 @@ func (x Const) String() string {
panic("unreachable")
}
-
func (x Const) UnaryOp(op token.Token) Const {
panic("unimplemented")
}
-
func (x Const) BinaryOp(op token.Token, y Const) Const {
var z interface{}
switch x := x.val.(type) {
@@ -194,7 +184,6 @@ func (x Const) BinaryOp(op token.Token, y Const) Const {
return Const{z}
}
-
func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
switch op {
case token.EQL:
@@ -205,7 +194,6 @@ func binaryBoolOp(x bool, op token.Token, y bool) interface{} {
panic("unreachable")
}
-
func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
var z big.Int
switch op {
@@ -247,7 +235,6 @@ func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} {
panic("unreachable")
}
-
func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
var z big.Rat
switch op {
@@ -275,7 +262,6 @@ func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} {
panic("unreachable")
}
-
func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
a, b := x.re, x.im
c, d := y.re, y.im
@@ -325,7 +311,6 @@ func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} {
panic("unreachable")
}
-
func binaryStringOp(x string, op token.Token, y string) interface{} {
switch op {
case token.ADD:
diff --git a/libgo/go/go/types/exportdata.go b/libgo/go/go/types/exportdata.go
index cb08ffe18a2..383520320f4 100644
--- a/libgo/go/go/types/exportdata.go
+++ b/libgo/go/go/types/exportdata.go
@@ -15,7 +15,6 @@ import (
"strings"
)
-
func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) {
// See $GOROOT/include/ar.h.
hdr := make([]byte, 64+12+6+6+8+10+2)
@@ -29,20 +28,18 @@ func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) {
s := strings.TrimSpace(string(hdr[64+12+6+6+8:][:10]))
size, err = strconv.Atoi(s)
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
- err = os.ErrorString("invalid archive header")
+ err = os.NewError("invalid archive header")
return
}
name = strings.TrimSpace(string(hdr[:64]))
return
}
-
type dataReader struct {
*bufio.Reader
io.Closer
}
-
// ExportData returns a readCloser positioned at the beginning of the
// export data section of the given object/archive file, or an error.
// It is the caller's responsibility to close the readCloser.
@@ -80,7 +77,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
return
}
if name != "__.SYMDEF" {
- err = os.ErrorString("go archive does not begin with __.SYMDEF")
+ err = os.NewError("go archive does not begin with __.SYMDEF")
return
}
const block = 4096
@@ -102,7 +99,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
return
}
if name != "__.PKGDEF" {
- err = os.ErrorString("go archive is missing __.PKGDEF")
+ err = os.NewError("go archive is missing __.PKGDEF")
return
}
@@ -117,7 +114,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
// Now at __.PKGDEF in archive or still at beginning of file.
// Either way, line should begin with "go object ".
if !strings.HasPrefix(string(line), "go object ") {
- err = os.ErrorString("not a go object file")
+ err = os.NewError("not a go object file")
return
}
diff --git a/libgo/go/go/types/gcimporter.go b/libgo/go/go/types/gcimporter.go
index 30adc04e729..6ab1806b643 100644
--- a/libgo/go/go/types/gcimporter.go
+++ b/libgo/go/go/types/gcimporter.go
@@ -20,7 +20,6 @@ import (
"strconv"
)
-
const trace = false // set to true for debugging
var (
@@ -28,7 +27,6 @@ var (
pkgExts = [...]string{".a", ".5", ".6", ".8"}
)
-
// findPkg returns the filename and package id for an import path.
// If no file was found, an empty filename is returned.
func findPkg(path string) (filename, id string) {
@@ -69,20 +67,17 @@ func findPkg(path string) (filename, id string) {
return
}
-
// gcParser parses the exports inside a gc compiler-produced
// object/archive file and populates its scope with the results.
type gcParser struct {
scanner scanner.Scanner
- tok int // current token
- lit string // literal string; only valid for Ident, Int, String tokens
- id string // package id of imported package
- scope *ast.Scope // scope of imported package; alias for deps[id]
- deps map[string]*ast.Scope // package id -> package scope
+ tok int // current token
+ lit string // literal string; only valid for Ident, Int, String tokens
+ id string // package id of imported package
+ imports map[string]*ast.Object // package id -> package object
}
-
-func (p *gcParser) init(filename, id string, src io.Reader) {
+func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*ast.Object) {
p.scanner.Init(src)
p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
@@ -90,11 +85,9 @@ func (p *gcParser) init(filename, id string, src io.Reader) {
p.scanner.Filename = filename // for good error messages
p.next()
p.id = id
- p.scope = ast.NewScope(nil)
- p.deps = map[string]*ast.Scope{"unsafe": Unsafe, id: p.scope}
+ p.imports = imports
}
-
func (p *gcParser) next() {
p.tok = p.scanner.Scan()
switch p.tok {
@@ -108,11 +101,10 @@ func (p *gcParser) next() {
}
}
-
// GcImporter implements the ast.Importer signature.
-func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) {
+func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, err os.Error) {
if path == "unsafe" {
- return path, Unsafe, nil
+ return Unsafe, nil
}
defer func() {
@@ -126,10 +118,14 @@ func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) {
filename, id := findPkg(path)
if filename == "" {
- err = os.ErrorString("can't find import: " + id)
+ err = os.NewError("can't find import: " + id)
return
}
+ if pkg = imports[id]; pkg != nil {
+ return // package was imported before
+ }
+
buf, err := ExportData(filename)
if err != nil {
return
@@ -137,17 +133,15 @@ func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) {
defer buf.Close()
if trace {
- fmt.Printf("importing %s\n", filename)
+ fmt.Printf("importing %s (%s)\n", id, filename)
}
var p gcParser
- p.init(filename, id, buf)
- name, scope = p.parseExport()
-
+ p.init(filename, id, buf, imports)
+ pkg = p.parseExport()
return
}
-
// ----------------------------------------------------------------------------
// Error handling
@@ -157,26 +151,22 @@ type importError struct {
err os.Error
}
-
func (e importError) String() string {
return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
}
-
func (p *gcParser) error(err interface{}) {
if s, ok := err.(string); ok {
- err = os.ErrorString(s)
+ err = os.NewError(s)
}
// panic with a runtime.Error if err is not an os.Error
panic(importError{p.scanner.Pos(), err.(os.Error)})
}
-
func (p *gcParser) errorf(format string, args ...interface{}) {
p.error(fmt.Sprintf(format, args...))
}
-
func (p *gcParser) expect(tok int) string {
lit := p.lit
if p.tok != tok {
@@ -186,7 +176,6 @@ func (p *gcParser) expect(tok int) string {
return lit
}
-
func (p *gcParser) expectSpecial(tok string) {
sep := 'x' // not white space
i := 0
@@ -200,7 +189,6 @@ func (p *gcParser) expectSpecial(tok string) {
}
}
-
func (p *gcParser) expectKeyword(keyword string) {
lit := p.expect(scanner.Ident)
if lit != keyword {
@@ -208,29 +196,37 @@ func (p *gcParser) expectKeyword(keyword string) {
}
}
-
// ----------------------------------------------------------------------------
// Import declarations
// ImportPath = string_lit .
//
-func (p *gcParser) parsePkgId() *ast.Scope {
+func (p *gcParser) parsePkgId() *ast.Object {
id, err := strconv.Unquote(p.expect(scanner.String))
if err != nil {
p.error(err)
}
- scope := p.scope // id == "" stands for the imported package id
- if id != "" {
- if scope = p.deps[id]; scope == nil {
- scope = ast.NewScope(nil)
- p.deps[id] = scope
- }
+ switch id {
+ case "":
+ // id == "" stands for the imported package id
+ // (only known at time of package installation)
+ id = p.id
+ case "unsafe":
+ // package unsafe is not in the imports map - handle explicitly
+ return Unsafe
}
- return scope
-}
+ pkg := p.imports[id]
+ if pkg == nil {
+ scope = ast.NewScope(nil)
+ pkg = ast.NewObj(ast.Pkg, "")
+ pkg.Data = scope
+ p.imports[id] = pkg
+ }
+ return pkg
+}
// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
func (p *gcParser) parseDotIdent() string {
@@ -249,17 +245,17 @@ func (p *gcParser) parseDotIdent() string {
return ident
}
-
// ExportedName = ImportPath "." dotIdentifier .
//
func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
- scope := p.parsePkgId()
+ pkg := p.parsePkgId()
p.expect('.')
name := p.parseDotIdent()
// a type may have been declared before - if it exists
// already in the respective package scope, return that
// type
+ scope := pkg.Data.(*ast.Scope)
if kind == ast.Typ {
if obj := scope.Lookup(name); obj != nil {
assert(obj.Kind == ast.Typ)
@@ -283,7 +279,6 @@ func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object {
return obj
}
-
// ----------------------------------------------------------------------------
// Types
@@ -297,7 +292,6 @@ func (p *gcParser) parseBasicType() Type {
return obj.Type.(Type)
}
-
// ArrayType = "[" int_lit "]" Type .
//
func (p *gcParser) parseArrayType() Type {
@@ -312,7 +306,6 @@ func (p *gcParser) parseArrayType() Type {
return &Array{Len: n, Elt: elt}
}
-
// MapType = "map" "[" Type "]" Type .
//
func (p *gcParser) parseMapType() Type {
@@ -324,7 +317,6 @@ func (p *gcParser) parseMapType() Type {
return &Map{Key: key, Elt: elt}
}
-
// Name = identifier | "?" .
//
func (p *gcParser) parseName() (name string) {
@@ -341,156 +333,171 @@ func (p *gcParser) parseName() (name string) {
return
}
-
// Field = Name Type [ ":" string_lit ] .
//
-func (p *gcParser) parseField(scope *ast.Scope) {
- // TODO(gri) The code below is not correct for anonymous fields:
- // The name is the type name; it should not be empty.
+func (p *gcParser) parseField() (fld *ast.Object, tag string) {
name := p.parseName()
ftyp := p.parseType()
if name == "" {
// anonymous field - ftyp must be T or *T and T must be a type name
- ftyp = Deref(ftyp)
- if ftyp, ok := ftyp.(*Name); ok {
- name = ftyp.Obj.Name
- } else {
+ if _, ok := Deref(ftyp).(*Name); !ok {
p.errorf("anonymous field expected")
}
}
if p.tok == ':' {
p.next()
- tag := p.expect(scanner.String)
- _ = tag // TODO(gri) store tag somewhere
+ tag = p.expect(scanner.String)
}
- fld := ast.NewObj(ast.Var, name)
+ fld = ast.NewObj(ast.Var, name)
fld.Type = ftyp
- scope.Insert(fld)
+ return
}
-
// StructType = "struct" "{" [ FieldList ] "}" .
// FieldList = Field { ";" Field } .
//
func (p *gcParser) parseStructType() Type {
+ var fields []*ast.Object
+ var tags []string
+
+ parseField := func() {
+ fld, tag := p.parseField()
+ fields = append(fields, fld)
+ tags = append(tags, tag)
+ }
+
p.expectKeyword("struct")
p.expect('{')
- scope := ast.NewScope(nil)
if p.tok != '}' {
- p.parseField(scope)
+ parseField()
for p.tok == ';' {
p.next()
- p.parseField(scope)
+ parseField()
}
}
p.expect('}')
- return &Struct{}
-}
+ return &Struct{Fields: fields, Tags: tags}
+}
-// Parameter = ( identifier | "?" ) [ "..." ] Type .
+// Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] .
//
-func (p *gcParser) parseParameter(scope *ast.Scope, isVariadic *bool) {
+func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) {
name := p.parseName()
if name == "" {
name = "_" // cannot access unnamed identifiers
}
- if isVariadic != nil {
- if *isVariadic {
- p.error("... not on final argument")
- }
- if p.tok == '.' {
- p.expectSpecial("...")
- *isVariadic = true
- }
+ if p.tok == '.' {
+ p.expectSpecial("...")
+ isVariadic = true
}
ptyp := p.parseType()
- par := ast.NewObj(ast.Var, name)
+ // ignore argument tag
+ if p.tok == ':' {
+ p.next()
+ p.expect(scanner.String)
+ }
+ par = ast.NewObj(ast.Var, name)
par.Type = ptyp
- scope.Insert(par)
+ return
}
-
// Parameters = "(" [ ParameterList ] ")" .
// ParameterList = { Parameter "," } Parameter .
//
-func (p *gcParser) parseParameters(scope *ast.Scope, isVariadic *bool) {
+func (p *gcParser) parseParameters() (list []*ast.Object, isVariadic bool) {
+ parseParameter := func() {
+ par, variadic := p.parseParameter()
+ list = append(list, par)
+ if variadic {
+ if isVariadic {
+ p.error("... not on final argument")
+ }
+ isVariadic = true
+ }
+ }
+
p.expect('(')
if p.tok != ')' {
- p.parseParameter(scope, isVariadic)
+ parseParameter()
for p.tok == ',' {
p.next()
- p.parseParameter(scope, isVariadic)
+ parseParameter()
}
}
p.expect(')')
-}
+ return
+}
// Signature = Parameters [ Result ] .
// Result = Type | Parameters .
//
-func (p *gcParser) parseSignature(scope *ast.Scope, isVariadic *bool) {
- p.parseParameters(scope, isVariadic)
+func (p *gcParser) parseSignature() *Func {
+ params, isVariadic := p.parseParameters()
// optional result type
+ var results []*ast.Object
switch p.tok {
case scanner.Ident, scanner.String, '[', '*', '<':
// single, unnamed result
result := ast.NewObj(ast.Var, "_")
result.Type = p.parseType()
- scope.Insert(result)
+ results = []*ast.Object{result}
case '(':
// named or multiple result(s)
- p.parseParameters(scope, nil)
+ var variadic bool
+ results, variadic = p.parseParameters()
+ if variadic {
+ p.error("... not permitted on result type")
+ }
}
-}
-
-// FuncType = "func" Signature .
-//
-func (p *gcParser) parseFuncType() Type {
- // "func" already consumed
- scope := ast.NewScope(nil)
- isVariadic := false
- p.parseSignature(scope, &isVariadic)
- return &Func{IsVariadic: isVariadic}
+ return &Func{Params: params, Results: results, IsVariadic: isVariadic}
}
-
// MethodSpec = identifier Signature .
//
-func (p *gcParser) parseMethodSpec(scope *ast.Scope) {
+func (p *gcParser) parseMethodSpec() *ast.Object {
if p.tok == scanner.Ident {
p.expect(scanner.Ident)
} else {
+ // TODO(gri) should this be parseExportedName here?
p.parsePkgId()
p.expect('.')
p.parseDotIdent()
}
- isVariadic := false
- p.parseSignature(scope, &isVariadic)
-}
+ p.parseSignature()
+ // TODO(gri) compute method object
+ return ast.NewObj(ast.Fun, "_")
+}
// InterfaceType = "interface" "{" [ MethodList ] "}" .
// MethodList = MethodSpec { ";" MethodSpec } .
//
func (p *gcParser) parseInterfaceType() Type {
+ var methods ObjList
+
+ parseMethod := func() {
+ meth := p.parseMethodSpec()
+ methods = append(methods, meth)
+ }
+
p.expectKeyword("interface")
p.expect('{')
- scope := ast.NewScope(nil)
if p.tok != '}' {
- p.parseMethodSpec(scope)
+ parseMethod()
for p.tok == ';' {
p.next()
- p.parseMethodSpec(scope)
+ parseMethod()
}
}
p.expect('}')
- return &Interface{}
-}
+ methods.Sort()
+ return &Interface{Methods: methods}
+}
// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
//
@@ -511,7 +518,6 @@ func (p *gcParser) parseChanType() Type {
return &Chan{Dir: dir, Elt: elt}
}
-
// Type =
// BasicType | TypeName | ArrayType | SliceType | StructType |
// PointerType | FuncType | InterfaceType | MapType | ChanType |
@@ -520,6 +526,7 @@ func (p *gcParser) parseChanType() Type {
// TypeName = ExportedName .
// SliceType = "[" "]" Type .
// PointerType = "*" Type .
+// FuncType = "func" Signature .
//
func (p *gcParser) parseType() Type {
switch p.tok {
@@ -530,8 +537,9 @@ func (p *gcParser) parseType() Type {
case "struct":
return p.parseStructType()
case "func":
- p.next() // parseFuncType assumes "func" is already consumed
- return p.parseFuncType()
+ // FuncType
+ p.next()
+ return p.parseSignature()
case "interface":
return p.parseInterfaceType()
case "map":
@@ -567,7 +575,6 @@ func (p *gcParser) parseType() Type {
return nil
}
-
// ----------------------------------------------------------------------------
// Declarations
@@ -578,12 +585,12 @@ func (p *gcParser) parseImportDecl() {
// The identifier has no semantic meaning in the import data.
// It exists so that error messages can print the real package
// name: binary.ByteOrder instead of "encoding/binary".ByteOrder.
- // TODO(gri): Save package id -> package name mapping.
- p.expect(scanner.Ident)
- p.parsePkgId()
+ name := p.expect(scanner.Ident)
+ pkg := p.parsePkgId()
+ assert(pkg.Name == "" || pkg.Name == name)
+ pkg.Name = name
}
-
// int_lit = [ "+" | "-" ] { "0" ... "9" } .
//
func (p *gcParser) parseInt() (sign, val string) {
@@ -598,7 +605,6 @@ func (p *gcParser) parseInt() (sign, val string) {
return
}
-
// number = int_lit [ "p" int_lit ] .
//
func (p *gcParser) parseNumber() Const {
@@ -629,7 +635,6 @@ func (p *gcParser) parseNumber() Const {
return Const{mant}
}
-
// ConstDecl = "const" ExportedName [ Type ] "=" Literal .
// Literal = bool_lit | int_lit | float_lit | complex_lit | string_lit .
// bool_lit = "true" | "false" .
@@ -681,24 +686,28 @@ func (p *gcParser) parseConstDecl() {
if obj.Type == nil {
obj.Type = typ
}
- _ = x // TODO(gri) store x somewhere
+ obj.Data = x
}
-
// TypeDecl = "type" ExportedName Type .
//
func (p *gcParser) parseTypeDecl() {
p.expectKeyword("type")
obj := p.parseExportedName(ast.Typ)
+
+ // The type object may have been imported before and thus already
+ // have a type associated with it. We still need to parse the type
+ // structure, but throw it away if the object already has a type.
+ // This ensures that all imports refer to the same type object for
+ // a given type declaration.
typ := p.parseType()
- name := obj.Type.(*Name)
- assert(name.Underlying == nil)
- assert(Underlying(typ) == typ)
- name.Underlying = typ
+ if name := obj.Type.(*Name); name.Underlying == nil {
+ assert(Underlying(typ) == typ)
+ name.Underlying = typ
+ }
}
-
// VarDecl = "var" ExportedName Type .
//
func (p *gcParser) parseVarDecl() {
@@ -707,32 +716,26 @@ func (p *gcParser) parseVarDecl() {
obj.Type = p.parseType()
}
-
// FuncDecl = "func" ExportedName Signature .
//
func (p *gcParser) parseFuncDecl() {
// "func" already consumed
obj := p.parseExportedName(ast.Fun)
- obj.Type = p.parseFuncType()
+ obj.Type = p.parseSignature()
}
-
// MethodDecl = "func" Receiver identifier Signature .
// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
//
func (p *gcParser) parseMethodDecl() {
// "func" already consumed
- scope := ast.NewScope(nil) // method scope
p.expect('(')
- p.parseParameter(scope, nil) // receiver
+ p.parseParameter() // receiver
p.expect(')')
p.expect(scanner.Ident)
- isVariadic := false
- p.parseSignature(scope, &isVariadic)
-
+ p.parseSignature()
}
-
// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
//
func (p *gcParser) parseDecl() {
@@ -756,14 +759,13 @@ func (p *gcParser) parseDecl() {
p.expect('\n')
}
-
// ----------------------------------------------------------------------------
// Export
// Export = "PackageClause { Decl } "$$" .
// PackageClause = "package" identifier [ "safe" ] "\n" .
//
-func (p *gcParser) parseExport() (string, *ast.Scope) {
+func (p *gcParser) parseExport() *ast.Object {
p.expectKeyword("package")
name := p.expect(scanner.Ident)
if p.tok != '\n' {
@@ -774,6 +776,11 @@ func (p *gcParser) parseExport() (string, *ast.Scope) {
}
p.expect('\n')
+ assert(p.imports[p.id] == nil)
+ pkg := ast.NewObj(ast.Pkg, name)
+ pkg.Data = ast.NewScope(nil)
+ p.imports[p.id] = pkg
+
for p.tok != '$' && p.tok != scanner.EOF {
p.parseDecl()
}
@@ -788,5 +795,5 @@ func (p *gcParser) parseExport() (string, *ast.Scope) {
p.errorf("expected no scanner errors, got %d", n)
}
- return name, p.scope
+ return pkg
}
diff --git a/libgo/go/go/types/gcimporter_test.go b/libgo/go/go/types/gcimporter_test.go
index 556e761df2d..ec87f5d514b 100644
--- a/libgo/go/go/types/gcimporter_test.go
+++ b/libgo/go/go/types/gcimporter_test.go
@@ -6,6 +6,7 @@ package types
import (
"exec"
+ "go/ast"
"io/ioutil"
"path/filepath"
"runtime"
@@ -14,7 +15,6 @@ import (
"time"
)
-
var gcName, gcPath string // compiler name and path
func init() {
@@ -34,31 +34,23 @@ func init() {
gcPath, _ = exec.LookPath(gcName)
}
-
func compile(t *testing.T, dirname, filename string) {
- cmd, err := exec.Run(gcPath, []string{gcPath, filename}, nil, dirname, exec.DevNull, exec.Pipe, exec.MergeWithStdout)
+ cmd := exec.Command(gcPath, filename)
+ cmd.Dir = dirname
+ out, err := cmd.CombinedOutput()
if err != nil {
t.Errorf("%s %s failed: %s", gcName, filename, err)
return
}
- defer cmd.Close()
-
- msg, err := cmd.Wait(0)
- if err != nil {
- t.Errorf("%s %s failed: %s", gcName, filename, err)
- return
- }
-
- if !msg.Exited() || msg.ExitStatus() != 0 {
- t.Errorf("%s %s failed: exit status = %d", gcName, filename, msg.ExitStatus())
- output, _ := ioutil.ReadAll(cmd.Stdout)
- t.Log(string(output))
- }
+ t.Logf("%s", string(out))
}
+// Use the same global imports map for all tests. The effect is
+// as if all tested packages were imported into a single package.
+var imports = make(map[string]*ast.Object)
func testPath(t *testing.T, path string) bool {
- _, _, err := GcImporter(path)
+ _, err := GcImporter(imports, path)
if err != nil {
t.Errorf("testPath(%s): %s", path, err)
return false
@@ -66,7 +58,6 @@ func testPath(t *testing.T, path string) bool {
return true
}
-
const maxTime = 3e9 // maximum allotted testing time in ns
func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
@@ -98,7 +89,6 @@ func testDir(t *testing.T, dir string, endTime int64) (nimports int) {
return
}
-
func TestGcImport(t *testing.T) {
compile(t, "testdata", "exports.go")
diff --git a/libgo/go/go/types/testdata/exports.go b/libgo/go/go/types/testdata/exports.go
index 13efe012a0b..ed63bf9adec 100644
--- a/libgo/go/go/types/testdata/exports.go
+++ b/libgo/go/go/types/testdata/exports.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This file is used to generate a .6 object file which
+// This file is used to generate an object file which
// serves as test file for gcimporter_test.go.
package exports
@@ -11,19 +11,17 @@ import (
"go/ast"
)
-
const (
C0 int = 0
- C1 = 3.14159265
- C2 = 2.718281828i
- C3 = -123.456e-789
- C4 = +123.456E+789
- C5 = 1234i
- C6 = "foo\n"
- C7 = `bar\n`
+ C1 = 3.14159265
+ C2 = 2.718281828i
+ C3 = -123.456e-789
+ C4 = +123.456E+789
+ C5 = 1234i
+ C6 = "foo\n"
+ C7 = `bar\n`
)
-
type (
T1 int
T2 [10]int
@@ -38,7 +36,7 @@ type (
T9 struct {
a int
b, c float32
- d []string "tag"
+ d []string `go:"tag"`
}
T10 struct {
T8
@@ -72,18 +70,15 @@ type (
T28 func(T28) T28
)
-
var (
V0 int
V1 = -991.0
)
-
func F1() {}
func F2(x int) {}
func F3() int { return 0 }
func F4() float32 { return 0 }
func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
-
func (p *T1) M1()
diff --git a/libgo/go/go/types/types.go b/libgo/go/go/types/types.go
index 2ee645d989b..3aa896892e3 100644
--- a/libgo/go/go/types/types.go
+++ b/libgo/go/go/types/types.go
@@ -7,21 +7,27 @@
//
package types
-import "go/ast"
-
+import (
+ "go/ast"
+ "sort"
+)
// All types implement the Type interface.
type Type interface {
isType()
}
-
// All concrete types embed ImplementsType which
// ensures that all types implement the Type interface.
type ImplementsType struct{}
func (t *ImplementsType) isType() {}
+// A Bad type is a non-nil placeholder type when we don't know a type.
+type Bad struct {
+ ImplementsType
+ Msg string // for better error reporting/debugging
+}
// A Basic represents a (unnamed) basic type.
type Basic struct {
@@ -29,7 +35,6 @@ type Basic struct {
// TODO(gri) need a field specifying the exact basic type
}
-
// An Array represents an array type [Len]Elt.
type Array struct {
ImplementsType
@@ -37,50 +42,52 @@ type Array struct {
Elt Type
}
-
// A Slice represents a slice type []Elt.
type Slice struct {
ImplementsType
Elt Type
}
-
// A Struct represents a struct type struct{...}.
+// Anonymous fields are represented by objects with empty names.
type Struct struct {
ImplementsType
- // TODO(gri) need to remember fields.
+ Fields ObjList // struct fields; or nil
+ Tags []string // corresponding tags; or nil
+ // TODO(gri) This type needs some rethinking:
+ // - at the moment anonymous fields are marked with "" object names,
+ // and their names have to be reconstructed
+ // - there is no scope for fast lookup (but the parser creates one)
}
-
// A Pointer represents a pointer type *Base.
type Pointer struct {
ImplementsType
Base Type
}
-
// A Func represents a function type func(...) (...).
+// Unnamed parameters are represented by objects with empty names.
type Func struct {
ImplementsType
- IsVariadic bool
- // TODO(gri) need to remember parameters.
+ Recv *ast.Object // nil if not a method
+ Params ObjList // (incoming) parameters from left to right; or nil
+ Results ObjList // (outgoing) results from left to right; or nil
+ IsVariadic bool // true if the last parameter's type is of the form ...T
}
-
// An Interface represents an interface type interface{...}.
type Interface struct {
ImplementsType
- // TODO(gri) need to remember methods.
+ Methods ObjList // interface methods sorted by name; or nil
}
-
// A Map represents a map type map[Key]Elt.
type Map struct {
ImplementsType
Key, Elt Type
}
-
// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt.
type Chan struct {
ImplementsType
@@ -88,7 +95,6 @@ type Chan struct {
Elt Type
}
-
// A Name represents a named type as declared in a type declaration.
type Name struct {
ImplementsType
@@ -97,7 +103,6 @@ type Name struct {
// TODO(gri) need to remember fields and methods.
}
-
// If typ is a pointer type, Deref returns the pointer's base type;
// otherwise it returns typ.
func Deref(typ Type) Type {
@@ -107,16 +112,144 @@ func Deref(typ Type) Type {
return typ
}
-
// Underlying returns the underlying type of a type.
func Underlying(typ Type) Type {
if typ, ok := typ.(*Name); ok {
utyp := typ.Underlying
- if _, ok := utyp.(*Basic); ok {
- return typ
+ if _, ok := utyp.(*Basic); !ok {
+ return utyp
}
- return utyp
-
+ // the underlying type of a type name referring
+ // to an (untyped) basic type is the basic type
+ // name
}
return typ
}
+
+// An ObjList represents an ordered (in some fashion) list of objects.
+type ObjList []*ast.Object
+
+// ObjList implements sort.Interface.
+func (list ObjList) Len() int { return len(list) }
+func (list ObjList) Less(i, j int) bool { return list[i].Name < list[j].Name }
+func (list ObjList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
+
+// Sort sorts an object list by object name.
+func (list ObjList) Sort() { sort.Sort(list) }
+
+// identicalTypes returns true if both lists a and b have the
+// same length and corresponding objects have identical types.
+func identicalTypes(a, b ObjList) bool {
+ if len(a) == len(b) {
+ for i, x := range a {
+ y := b[i]
+ if !Identical(x.Type.(Type), y.Type.(Type)) {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+}
+
+// Identical returns true if two types are identical.
+func Identical(x, y Type) bool {
+ if x == y {
+ return true
+ }
+
+ switch x := x.(type) {
+ case *Bad:
+ // A Bad type is always identical to any other type
+ // (to avoid spurious follow-up errors).
+ return true
+
+ case *Basic:
+ if y, ok := y.(*Basic); ok {
+ panic("unimplemented")
+ _ = y
+ }
+
+ case *Array:
+ // Two array types are identical if they have identical element types
+ // and the same array length.
+ if y, ok := y.(*Array); ok {
+ return x.Len == y.Len && Identical(x.Elt, y.Elt)
+ }
+
+ case *Slice:
+ // Two slice types are identical if they have identical element types.
+ if y, ok := y.(*Slice); ok {
+ return Identical(x.Elt, y.Elt)
+ }
+
+ case *Struct:
+ // Two struct types are identical if they have the same sequence of fields,
+ // and if corresponding fields have the same names, and identical types,
+ // and identical tags. Two anonymous fields are considered to have the same
+ // name. Lower-case field names from different packages are always different.
+ if y, ok := y.(*Struct); ok {
+ // TODO(gri) handle structs from different packages
+ if identicalTypes(x.Fields, y.Fields) {
+ for i, f := range x.Fields {
+ g := y.Fields[i]
+ if f.Name != g.Name || x.Tags[i] != y.Tags[i] {
+ return false
+ }
+ }
+ return true
+ }
+ }
+
+ case *Pointer:
+ // Two pointer types are identical if they have identical base types.
+ if y, ok := y.(*Pointer); ok {
+ return Identical(x.Base, y.Base)
+ }
+
+ case *Func:
+ // Two function types are identical if they have the same number of parameters
+ // and result values, corresponding parameter and result types are identical,
+ // and either both functions are variadic or neither is. Parameter and result
+ // names are not required to match.
+ if y, ok := y.(*Func); ok {
+ return identicalTypes(x.Params, y.Params) &&
+ identicalTypes(x.Results, y.Results) &&
+ x.IsVariadic == y.IsVariadic
+ }
+
+ case *Interface:
+ // Two interface types are identical if they have the same set of methods with
+ // the same names and identical function types. Lower-case method names from
+ // different packages are always different. The order of the methods is irrelevant.
+ if y, ok := y.(*Interface); ok {
+ return identicalTypes(x.Methods, y.Methods) // methods are sorted
+ }
+
+ case *Map:
+ // Two map types are identical if they have identical key and value types.
+ if y, ok := y.(*Map); ok {
+ return Identical(x.Key, y.Key) && Identical(x.Elt, y.Elt)
+ }
+
+ case *Chan:
+ // Two channel types are identical if they have identical value types
+ // and the same direction.
+ if y, ok := y.(*Chan); ok {
+ return x.Dir == y.Dir && Identical(x.Elt, y.Elt)
+ }
+
+ case *Name:
+ // Two named types are identical if their type names originate
+ // in the same type declaration.
+ if y, ok := y.(*Name); ok {
+ return x.Obj == y.Obj ||
+ // permit bad objects to be equal to avoid
+ // follow up errors
+ x.Obj != nil && x.Obj.Kind == ast.Bad ||
+ y.Obj != nil && y.Obj.Kind == ast.Bad
+ }
+ }
+
+ return false
+}
diff --git a/libgo/go/go/types/universe.go b/libgo/go/go/types/universe.go
index 2a54a8ac12c..6ae88e5f9c2 100644
--- a/libgo/go/go/types/universe.go
+++ b/libgo/go/go/types/universe.go
@@ -9,14 +9,12 @@ package types
import "go/ast"
-
var (
- scope, // current scope to use for initialization
- Universe,
- Unsafe *ast.Scope
+ scope *ast.Scope // current scope to use for initialization
+ Universe *ast.Scope
+ Unsafe *ast.Object // package unsafe
)
-
func define(kind ast.ObjKind, name string) *ast.Object {
obj := ast.NewObj(kind, name)
if scope.Insert(obj) != nil {
@@ -25,7 +23,6 @@ func define(kind ast.ObjKind, name string) *ast.Object {
return obj
}
-
func defType(name string) *Name {
obj := define(ast.Typ, name)
typ := &Name{Underlying: &Basic{}, Obj: obj}
@@ -33,19 +30,16 @@ func defType(name string) *Name {
return typ
}
-
func defConst(name string) {
obj := define(ast.Con, name)
_ = obj // TODO(gri) fill in other properties
}
-
func defFun(name string) {
obj := define(ast.Fun, name)
_ = obj // TODO(gri) fill in other properties
}
-
var (
Bool,
Int,
@@ -54,10 +48,9 @@ var (
String *Name
)
-
func init() {
- Universe = ast.NewScope(nil)
- scope = Universe
+ scope = ast.NewScope(nil)
+ Universe = scope
Bool = defType("bool")
defType("byte") // TODO(gri) should be an alias for uint8
@@ -98,8 +91,10 @@ func init() {
defFun("real")
defFun("recover")
- Unsafe = ast.NewScope(nil)
- scope = Unsafe
+ scope = ast.NewScope(nil)
+ Unsafe = ast.NewObj(ast.Pkg, "unsafe")
+ Unsafe.Data = scope
+
defType("Pointer")
defFun("Alignof")
diff --git a/libgo/go/gob/codec_test.go b/libgo/go/gob/codec_test.go
index 8961336cd34..a5fb91cda78 100644
--- a/libgo/go/gob/codec_test.go
+++ b/libgo/go/gob/codec_test.go
@@ -330,7 +330,7 @@ func newDecodeStateFromData(data []byte) *decoderState {
// Test instruction execution for decoding.
// Do not run the machine yet; instead do individual instructions crafted by hand.
func TestScalarDecInstructions(t *testing.T) {
- ovfl := os.ErrorString("overflow")
+ ovfl := os.NewError("overflow")
// bool
{
@@ -573,30 +573,32 @@ func TestEndToEnd(t *testing.T) {
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
+ A, B, C int
+ M map[string]*float64
+ EmptyMap map[string]int // to check that we receive a non-nil map.
+ 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"},
+ A: 17,
+ B: 18,
+ C: -5,
+ M: map[string]*float64{"pi": &pi, "e": &e},
+ EmptyMap: make(map[string]int),
+ 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)
@@ -611,6 +613,13 @@ func TestEndToEnd(t *testing.T) {
if !reflect.DeepEqual(t1, &_t1) {
t.Errorf("encode expected %v got %v", *t1, _t1)
}
+ // Be absolutely sure the received map is non-nil.
+ if t1.EmptyMap == nil {
+ t.Errorf("nil map sent")
+ }
+ if _t1.EmptyMap == nil {
+ t.Errorf("nil map received")
+ }
}
func TestOverflow(t *testing.T) {
@@ -782,7 +791,6 @@ func TestOverflow(t *testing.T) {
}
}
-
func TestNesting(t *testing.T) {
type RT struct {
A string
@@ -980,7 +988,6 @@ func TestIgnoredFields(t *testing.T) {
}
}
-
func TestBadRecursiveType(t *testing.T) {
type Rec ***Rec
var rec Rec
diff --git a/libgo/go/gob/decode.go b/libgo/go/gob/decode.go
index 0e86df6b57a..bf7cb95f22c 100644
--- a/libgo/go/gob/decode.go
+++ b/libgo/go/gob/decode.go
@@ -17,9 +17,9 @@ import (
)
var (
- errBadUint = os.ErrorString("gob: encoded unsigned integer out of range")
- errBadType = os.ErrorString("gob: unknown type id or corrupted data")
- errRange = os.ErrorString("gob: bad data: field numbers out of bounds")
+ errBadUint = os.NewError("gob: encoded unsigned integer out of range")
+ errBadType = os.NewError("gob: unknown type id or corrupted data")
+ errRange = os.NewError("gob: bad data: field numbers out of bounds")
)
// decoderState is the execution state of an instance of the decoder. A new state
@@ -54,8 +54,8 @@ func (dec *Decoder) freeDecoderState(d *decoderState) {
dec.freeList = d
}
-func overflow(name string) os.ErrorString {
- return os.ErrorString(`value for "` + name + `" out of range`)
+func overflow(name string) os.Error {
+ return os.NewError(`value for "` + name + `" out of range`)
}
// decodeUintReader reads an encoded unsigned integer from an io.Reader.
@@ -135,10 +135,10 @@ type decOp func(i *decInstr, state *decoderState, p unsafe.Pointer)
// The 'instructions' of the decoding machine
type decInstr struct {
op decOp
- field int // field number of the wire type
- indir int // how many pointer indirections to reach the value in the struct
- offset uintptr // offset in the structure of the field to encode
- ovfl os.ErrorString // error message for overflow/underflow (for arrays, of the elements)
+ field int // field number of the wire type
+ indir int // how many pointer indirections to reach the value in the struct
+ offset uintptr // offset in the structure of the field to encode
+ ovfl os.Error // error message for overflow/underflow (for arrays, of the elements)
}
// Since the encoder writes no zeros, if we arrive at a decoder we have
@@ -172,7 +172,7 @@ func ignoreTwoUints(i *decInstr, state *decoderState, p unsafe.Pointer) {
state.decodeUint()
}
-// decBool decodes a uiint and stores it as a boolean through p.
+// decBool decodes a uint and stores it as a boolean through p.
func decBool(i *decInstr, state *decoderState, p unsafe.Pointer) {
if i.indir > 0 {
if *(*unsafe.Pointer)(p) == nil {
@@ -367,7 +367,7 @@ func decComplex64(i *decInstr, state *decoderState, p unsafe.Pointer) {
p = *(*unsafe.Pointer)(p)
}
storeFloat32(i, state, p)
- storeFloat32(i, state, unsafe.Pointer(uintptr(p)+uintptr(unsafe.Sizeof(float32(0)))))
+ storeFloat32(i, state, unsafe.Pointer(uintptr(p)+unsafe.Sizeof(float32(0))))
}
// decComplex128 decodes a pair of unsigned integers, treats them as a
@@ -552,7 +552,7 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) {
}
// decodeArrayHelper does the work for decoding arrays and slices.
-func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) {
+func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.Error) {
instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
for i := 0; i < length; i++ {
up := unsafe.Pointer(p)
@@ -567,7 +567,7 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp dec
// decodeArray decodes an array and stores it through p, that is, p points to the zeroth element.
// The length is an unsigned integer preceding the elements. Even though the length is redundant
// (it's part of the type), it's a useful check and is included in the encoding.
-func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) {
+func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.Error) {
if indir > 0 {
p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
@@ -579,7 +579,7 @@ func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintpt
// decodeIntoValue is a helper for map decoding. Since maps are decoded using reflection,
// unlike the other items we can't use a pointer directly.
-func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl os.ErrorString) reflect.Value {
+func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl os.Error) reflect.Value {
instr := &decInstr{op, 0, indir, 0, ovfl}
up := unsafe.Pointer(unsafeAddr(v))
if indir > 1 {
@@ -593,7 +593,7 @@ func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value,
// Maps are encoded as a length followed by key:value pairs.
// Because the internals of maps are not visible to us, we must
// use reflection rather than pointer magic.
-func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) {
+func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.Error) {
if indir > 0 {
p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
@@ -616,7 +616,7 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr,
// ignoreArrayHelper does the work for discarding arrays and slices.
func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
- instr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
+ instr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")}
for i := 0; i < length; i++ {
elemOp(instr, state, nil)
}
@@ -633,8 +633,8 @@ func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) {
// ignoreMap discards the data for a map value with no destination.
func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
n := int(state.decodeUint())
- keyInstr := &decInstr{keyOp, 0, 0, 0, os.ErrorString("no error")}
- elemInstr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
+ keyInstr := &decInstr{keyOp, 0, 0, 0, os.NewError("no error")}
+ elemInstr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")}
for i := 0; i < n; i++ {
keyOp(keyInstr, state, nil)
elemOp(elemInstr, state, nil)
@@ -643,7 +643,7 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
// decodeSlice decodes a slice and stores the slice header through p.
// Slices are encoded as an unsigned length followed by the elements.
-func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) {
+func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.Error) {
n := int(uintptr(state.decodeUint()))
if indir > 0 {
up := unsafe.Pointer(p)
@@ -741,7 +741,7 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
// decodeGobDecoder decodes something implementing the GobDecoder interface.
// The data is encoded as a byte slice.
-func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value, index int) {
+func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value) {
// Read the bytes for the value.
b := make([]byte, state.decodeUint())
_, err := state.b.Read(b)
@@ -969,7 +969,7 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) {
} else {
v = reflect.ValueOf(unsafe.Unreflect(rcvrType, p))
}
- state.dec.decodeGobDecoder(state, v, methodIndex(rcvrType, gobDecodeMethodName))
+ state.dec.decodeGobDecoder(state, v)
}
return &op, int(ut.indir)
@@ -1064,10 +1064,10 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
engine.instr = make([]decInstr, 1) // one item
name := rt.String() // best we can do
if !dec.compatibleType(rt, remoteId, make(map[reflect.Type]typeId)) {
- return nil, os.ErrorString("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
+ return nil, os.NewError("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
}
op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
- ovfl := os.ErrorString(`value for "` + name + `" out of range`)
+ ovfl := os.NewError(`value for "` + name + `" out of range`)
engine.instr[singletonField] = decInstr{*op, singletonField, indir, 0, ovfl}
engine.numInstr = 1
return
diff --git a/libgo/go/gob/decoder.go b/libgo/go/gob/decoder.go
index ea2f62ec503..28194713225 100644
--- a/libgo/go/gob/decoder.go
+++ b/libgo/go/gob/decoder.go
@@ -44,7 +44,7 @@ func NewDecoder(r io.Reader) *Decoder {
func (dec *Decoder) recvType(id typeId) {
// Have we already seen this type? That's an error
if id < firstUserId || dec.wireType[id] != nil {
- dec.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.NewError("gob: duplicate type received")
return
}
@@ -143,7 +143,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// will be absorbed by recvMessage.)
if dec.buf.Len() > 0 {
if !isInterface {
- dec.err = os.ErrorString("extra data in buffer")
+ dec.err = os.NewError("extra data in buffer")
break
}
dec.nextUint()
@@ -155,8 +155,8 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// Decode reads the next value from the connection and stores
// it in the data represented by the empty interface value.
// If e is nil, the value will be discarded. Otherwise,
-// the value underlying e must either be the correct type for the next
-// data item received, and must be a pointer.
+// the value underlying e must be a pointer to the
+// correct type for the next data item received.
func (dec *Decoder) Decode(e interface{}) os.Error {
if e == nil {
return dec.DecodeValue(reflect.Value{})
@@ -165,7 +165,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
- dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ dec.err = os.NewError("gob: attempt to decode into a non-pointer")
return dec.err
}
return dec.DecodeValue(value)
@@ -180,7 +180,7 @@ func (dec *Decoder) DecodeValue(v reflect.Value) os.Error {
if v.Kind() == reflect.Ptr && !v.IsNil() {
// That's okay, we'll store through the pointer.
} else if !v.CanSet() {
- return os.ErrorString("gob: DecodeValue of unassignable value")
+ return os.NewError("gob: DecodeValue of unassignable value")
}
}
// Make sure we're single-threaded through here.
diff --git a/libgo/go/gob/doc.go b/libgo/go/gob/doc.go
index 850759bbda6..35d882afb7a 100644
--- a/libgo/go/gob/doc.go
+++ b/libgo/go/gob/doc.go
@@ -29,29 +29,29 @@ 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 }
+ 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
+ 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.
+ 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 { 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
+ 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.
@@ -113,6 +113,11 @@ 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.
+Maps are sent as an unsigned count followed by that man key, element
+pairs. Empty but non-nil maps are sent, so if the sender has allocated
+a map, the receiver will allocate a map even no elements are
+transmitted.
+
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
@@ -269,12 +274,12 @@ StructValue:
/*
For implementers and the curious, here is an encoded example. Given
- type Point struct {x, y int}
+ 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
+ 01 02 01 01 58 01 04 00 01 01 59 01 04 00 00 00
07 ff 82 01 2c 01 42 00
They are determined as follows.
@@ -310,13 +315,13 @@ reserved).
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"
+ 58 // 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"
+ 59 // 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.
diff --git a/libgo/go/gob/encode.go b/libgo/go/gob/encode.go
index f9e691a2fa6..317014efdad 100644
--- a/libgo/go/gob/encode.go
+++ b/libgo/go/gob/encode.go
@@ -11,7 +11,7 @@ import (
"unsafe"
)
-const uint64Size = unsafe.Sizeof(uint64(0))
+const uint64Size = int(unsafe.Sizeof(uint64(0)))
// encoderState is the global execution state of an instance of the encoder.
// Field numbers are delta encoded and always increase. The field
@@ -62,7 +62,7 @@ func (state *encoderState) encodeUint(x uint64) {
var n, m int
m = uint64Size
for n = 1; x > 0; n++ {
- state.buf[m] = uint8(x & 0xFF)
+ state.buf[m] = uint8(x)
x >>= 8
m--
}
@@ -466,9 +466,30 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
enc.freeEncoderState(state)
}
+// isZero returns whether the value is the zero of its type.
+func isZero(val reflect.Value) bool {
+ switch val.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return val.Len() == 0
+ case reflect.Bool:
+ return !val.Bool()
+ case reflect.Complex64, reflect.Complex128:
+ return val.Complex() == 0
+ case reflect.Chan, reflect.Func, reflect.Ptr:
+ return val.IsNil()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return val.Int() == 0
+ case reflect.Float32, reflect.Float64:
+ return val.Float() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return val.Uint() == 0
+ }
+ panic("unknown type in isZero " + val.Type().String())
+}
+
// encGobEncoder encodes a value that implements the GobEncoder interface.
// The data is sent as a byte array.
-func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value, index int) {
+func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value) {
// TODO: should we catch panics from the called method?
// We know it's a GobEncoder, so just call the method directly.
data, err := v.Interface().(GobEncoder).GobEncode()
@@ -557,7 +578,9 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
// the iteration.
v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p)))
mv := reflect.Indirect(v)
- if !state.sendZero && mv.Len() == 0 {
+ // We send zero-length (but non-nil) maps because the
+ // receiver might want to use the map. (Maps don't use append.)
+ if !state.sendZero && mv.IsNil() {
return
}
state.update(i)
@@ -592,17 +615,6 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp
return &op, indir
}
-// methodIndex returns which method of rt implements the method.
-func methodIndex(rt reflect.Type, method string) int {
- for i := 0; i < rt.NumMethod(); i++ {
- if rt.Method(i).Name == method {
- return i
- }
- }
- errorf("internal error: can't find method %s", method)
- return 0
-}
-
// gobEncodeOpFor returns the op for a type that is known to implement
// GobEncoder.
func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
@@ -623,8 +635,11 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) {
} else {
v = reflect.ValueOf(unsafe.Unreflect(rt, p))
}
+ if !state.sendZero && isZero(v) {
+ return
+ }
state.update(i)
- state.enc.encodeGobEncoder(state.b, v, methodIndex(rt, gobEncodeMethodName))
+ state.enc.encodeGobEncoder(state.b, v)
}
return &op, int(ut.encIndir) // encIndir: op will get called with p == address of receiver.
}
diff --git a/libgo/go/gob/encoder.go b/libgo/go/gob/encoder.go
index 65ee5bf67c8..96101d92bab 100644
--- a/libgo/go/gob/encoder.go
+++ b/libgo/go/gob/encoder.go
@@ -50,7 +50,7 @@ func (enc *Encoder) popWriter() {
}
func (enc *Encoder) badType(rt reflect.Type) {
- enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
+ enc.setError(os.NewError("gob: can't encode type " + rt.String()))
}
func (enc *Encoder) setError(err os.Error) {
diff --git a/libgo/go/gob/encoder_test.go b/libgo/go/gob/encoder_test.go
index 792afbd7752..f5ee423cb2b 100644
--- a/libgo/go/gob/encoder_test.go
+++ b/libgo/go/gob/encoder_test.go
@@ -549,3 +549,32 @@ func TestMapBug1(t *testing.T) {
t.Errorf("mismatch: %v %v", in, out)
}
}
+
+func TestGobMapInterfaceEncode(t *testing.T) {
+ m := map[string]interface{}{
+ "up": uintptr(0),
+ "i0": []int{-1},
+ "i1": []int8{-1},
+ "i2": []int16{-1},
+ "i3": []int32{-1},
+ "i4": []int64{-1},
+ "u0": []uint{1},
+ "u1": []uint8{1},
+ "u2": []uint16{1},
+ "u3": []uint32{1},
+ "u4": []uint64{1},
+ "f0": []float32{1},
+ "f1": []float64{1},
+ "c0": []complex64{complex(2, -2)},
+ "c1": []complex128{complex(2, float64(-2))},
+ "us": []uintptr{0},
+ "bo": []bool{false},
+ "st": []string{"s"},
+ }
+ buf := bytes.NewBuffer(nil)
+ enc := NewEncoder(buf)
+ err := enc.Encode(m)
+ if err != nil {
+ t.Errorf("gob.Encode map: %s", err)
+ }
+}
diff --git a/libgo/go/gob/gobencdec_test.go b/libgo/go/gob/gobencdec_test.go
index e94534f4c33..371a43c8f54 100644
--- a/libgo/go/gob/gobencdec_test.go
+++ b/libgo/go/gob/gobencdec_test.go
@@ -44,7 +44,7 @@ func (g *ByteStruct) GobEncode() ([]byte, os.Error) {
func (g *ByteStruct) GobDecode(data []byte) os.Error {
if g == nil {
- return os.ErrorString("NIL RECEIVER")
+ return os.NewError("NIL RECEIVER")
}
// Expect N sequential-valued bytes.
if len(data) == 0 {
@@ -53,7 +53,7 @@ func (g *ByteStruct) GobDecode(data []byte) os.Error {
g.a = data[0]
for i, c := range data {
if c != g.a+byte(i) {
- return os.ErrorString("invalid data sequence")
+ return os.NewError("invalid data sequence")
}
}
return nil
@@ -71,7 +71,7 @@ func (g *StringStruct) GobDecode(data []byte) os.Error {
a := data[0]
for i, c := range data {
if c != a+byte(i) {
- return os.ErrorString("invalid data sequence")
+ return os.NewError("invalid data sequence")
}
}
g.s = string(data)
@@ -84,7 +84,7 @@ func (a *ArrayStruct) GobEncode() ([]byte, os.Error) {
func (a *ArrayStruct) GobDecode(data []byte) os.Error {
if len(data) != len(a.a) {
- return os.ErrorString("wrong length in array decode")
+ return os.NewError("wrong length in array decode")
}
copy(a.a[:], data)
return nil
@@ -384,7 +384,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
y := &GobTest1{}
err = dec.Decode(y)
if err == nil {
- t.Fatal("expected decode error for mistmatched fields (non-encoder to decoder)")
+ t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)")
}
if strings.Index(err.String(), "type") < 0 {
t.Fatal("expected type error; got", err)
@@ -466,3 +466,25 @@ func TestGobEncoderIgnoreNonStructField(t *testing.T) {
t.Errorf("expected 17 got %c", x.X)
}
}
+
+func TestGobEncoderIgnoreNilEncoder(t *testing.T) {
+ b := new(bytes.Buffer)
+ // First a field that's a structure.
+ enc := NewEncoder(b)
+ err := enc.Encode(GobTest0{X: 18}) // G is nil
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+ dec := NewDecoder(b)
+ x := new(GobTest0)
+ err = dec.Decode(x)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if x.X != 18 {
+ t.Errorf("expected x.X = 18, got %v", x.X)
+ }
+ if x.G != nil {
+ t.Errorf("expected x.G = nil, got %v", x.G)
+ }
+}
diff --git a/libgo/go/gob/timing_test.go b/libgo/go/gob/timing_test.go
index 645f4fe51c9..2a2be73364d 100644
--- a/libgo/go/gob/timing_test.go
+++ b/libgo/go/gob/timing_test.go
@@ -53,6 +53,7 @@ func TestCountEncodeMallocs(t *testing.T) {
var buf bytes.Buffer
enc := NewEncoder(&buf)
bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
+ runtime.UpdateMemStats()
mallocs := 0 - runtime.MemStats.Mallocs
const count = 1000
for i := 0; i < count; i++ {
@@ -61,6 +62,7 @@ func TestCountEncodeMallocs(t *testing.T) {
t.Fatal("encode:", err)
}
}
+ runtime.UpdateMemStats()
mallocs += runtime.MemStats.Mallocs
fmt.Printf("mallocs per encode of type Bench: %d\n", mallocs/count)
}
@@ -77,6 +79,7 @@ func TestCountDecodeMallocs(t *testing.T) {
}
}
dec := NewDecoder(&buf)
+ runtime.UpdateMemStats()
mallocs := 0 - runtime.MemStats.Mallocs
for i := 0; i < count; i++ {
*bench = Bench{}
@@ -85,6 +88,7 @@ func TestCountDecodeMallocs(t *testing.T) {
t.Fatal("decode:", err)
}
}
+ runtime.UpdateMemStats()
mallocs += runtime.MemStats.Mallocs
fmt.Printf("mallocs per decode of type Bench: %d\n", mallocs/count)
}
diff --git a/libgo/go/gob/type.go b/libgo/go/gob/type.go
index c5b8fb5d9d1..b2f716c4b5d 100644
--- a/libgo/go/gob/type.go
+++ b/libgo/go/gob/type.go
@@ -67,7 +67,7 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
ut.base = pt.Elem()
if ut.base == slowpoke { // ut.base lapped slowpoke
// recursive pointer type.
- return nil, os.ErrorString("can't represent recursive pointer type " + ut.base.String())
+ return nil, os.NewError("can't represent recursive pointer type " + ut.base.String())
}
if ut.indir%2 == 0 {
slowpoke = slowpoke.Elem()
@@ -80,14 +80,9 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
return
}
-const (
- gobEncodeMethodName = "GobEncode"
- gobDecodeMethodName = "GobDecode"
-)
-
var (
- gobEncoderInterfaceType = reflect.TypeOf(new(GobEncoder)).Elem()
- gobDecoderInterfaceType = reflect.TypeOf(new(GobDecoder)).Elem()
+ gobEncoderInterfaceType = reflect.TypeOf((*GobEncoder)(nil)).Elem()
+ gobDecoderInterfaceType = reflect.TypeOf((*GobDecoder)(nil)).Elem()
)
// implementsInterface reports whether the type implements the
@@ -508,7 +503,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.
return st, nil
default:
- return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
+ return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
}
return nil, nil
}
@@ -673,7 +668,7 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo {
// A type that implements GobEncoder and GobDecoder has complete
// control over the representation of its data and may therefore
// contain things such as private fields, channels, and functions,
-// which are not usually transmissable in gob streams.
+// which are not usually transmissible in gob streams.
//
// Note: Since gobs can be stored permanently, It is good design
// to guarantee the encoding used by a GobEncoder is stable as the
@@ -767,7 +762,25 @@ func registerBasics() {
Register(float64(0))
Register(complex64(0i))
Register(complex128(0i))
+ Register(uintptr(0))
Register(false)
Register("")
Register([]byte(nil))
+ Register([]int(nil))
+ Register([]int8(nil))
+ Register([]int16(nil))
+ Register([]int32(nil))
+ Register([]int64(nil))
+ Register([]uint(nil))
+ Register([]uint8(nil))
+ Register([]uint16(nil))
+ Register([]uint32(nil))
+ Register([]uint64(nil))
+ Register([]float32(nil))
+ Register([]float64(nil))
+ Register([]complex64(nil))
+ Register([]complex128(nil))
+ Register([]uintptr(nil))
+ Register([]bool(nil))
+ Register([]string(nil))
}
diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go
index 88a44997168..0245b1ee8a8 100644
--- a/libgo/go/hash/crc32/crc32.go
+++ b/libgo/go/hash/crc32/crc32.go
@@ -10,6 +10,7 @@ package crc32
import (
"hash"
"os"
+ "sync"
)
// The size of a CRC-32 checksum in bytes.
@@ -35,8 +36,34 @@ const (
// Table is a 256-word table representing the polynomial for efficient processing.
type Table [256]uint32
+// castagnoliTable points to a lazily initialized Table for the Castagnoli
+// polynomial. MakeTable will always return this value when asked to make a
+// Castagnoli table so we can compare against it to find when the caller is
+// using this polynomial.
+var castagnoliTable *Table
+var castagnoliOnce sync.Once
+
+func castagnoliInit() {
+ castagnoliTable = makeTable(Castagnoli)
+}
+
+// IEEETable is the table for the IEEE polynomial.
+var IEEETable = makeTable(IEEE)
+
// MakeTable returns the Table constructed from the specified polynomial.
func MakeTable(poly uint32) *Table {
+ switch poly {
+ case IEEE:
+ return IEEETable
+ case Castagnoli:
+ castagnoliOnce.Do(castagnoliInit)
+ return castagnoliTable
+ }
+ return makeTable(poly)
+}
+
+// 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)
@@ -52,9 +79,6 @@ func MakeTable(poly uint32) *Table {
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
@@ -83,11 +107,14 @@ func update(crc uint32, tab *Table, p []byte) uint32 {
// Update returns the result of adding the bytes in p to the crc.
func Update(crc uint32, tab *Table, p []byte) uint32 {
+ if tab == castagnoliTable {
+ return updateCastagnoli(crc, p)
+ }
return update(crc, tab, p)
}
func (d *digest) Write(p []byte) (n int, err os.Error) {
- d.crc = update(d.crc, d.tab, p)
+ d.crc = Update(d.crc, d.tab, p)
return len(p), nil
}
@@ -105,7 +132,7 @@ func (d *digest) Sum() []byte {
// 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) }
+func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
// ChecksumIEEE returns the CRC-32 checksum of data
// using the IEEE polynomial.
diff --git a/libgo/go/hash/crc32/crc32_amd64.go b/libgo/go/hash/crc32/crc32_amd64.go
new file mode 100644
index 00000000000..83349bc6c22
--- /dev/null
+++ b/libgo/go/hash/crc32/crc32_amd64.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.
+
+package crc32
+
+// This file contains the code to call the SSE 4.2 version of the Castagnoli
+// CRC.
+
+// haveSSE42 is defined in crc_amd64.s and uses CPUID to test for SSE 4.2
+// support.
+func haveSSE42() bool
+
+// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// instruction.
+func castagnoliSSE42(uint32, []byte) uint32
+
+var sse42 = haveSSE42()
+
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+ if sse42 {
+ return castagnoliSSE42(crc, p)
+ }
+ return update(crc, castagnoliTable, p)
+}
diff --git a/libgo/go/hash/crc32/crc32_generic.go b/libgo/go/hash/crc32/crc32_generic.go
new file mode 100644
index 00000000000..27aabd903bb
--- /dev/null
+++ b/libgo/go/hash/crc32/crc32_generic.go
@@ -0,0 +1,12 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package crc32
+
+// The file contains the generic version of updateCastagnoli which just calls
+// the software implementation.
+
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+ return update(crc, castagnoliTable, p)
+}
diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go
index cf5743c992f..7e82dd755e7 100644
--- a/libgo/go/hash/crc32/crc32_test.go
+++ b/libgo/go/hash/crc32/crc32_test.go
@@ -10,53 +10,73 @@ import (
)
type test struct {
- out uint32
- in string
+ ieee, castagnoli 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"},
+ {0x0, 0x0, ""},
+ {0xe8b7be43, 0xc1d04330, "a"},
+ {0x9e83486d, 0xe2a22936, "ab"},
+ {0x352441c2, 0x364b3fb7, "abc"},
+ {0xed82cd11, 0x92c80a31, "abcd"},
+ {0x8587d865, 0xc450d697, "abcde"},
+ {0x4b8e39ef, 0x53bceff1, "abcdef"},
+ {0x312a6aa6, 0xe627f441, "abcdefg"},
+ {0xaeef2a50, 0xa9421b7, "abcdefgh"},
+ {0x8da988af, 0x2ddc99fc, "abcdefghi"},
+ {0x3981703a, 0xe6599437, "abcdefghij"},
+ {0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."},
+ {0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."},
+ {0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."},
+ {0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x4c418325, 0x85d3dc82, "Nepal premier won't resign."},
+ {0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."},
+ {0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0xab3abe14, 0x572b74e2, "size: a.out: bad magic"},
+ {0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail. -Mark Horton"},
+ {0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."},
+ {0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"},
+ {0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0x8e0bb443, 0xdcded527, "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()
+ castagnoliTab := MakeTable(Castagnoli)
+
+ for _, g := range golden {
+ ieee := NewIEEE()
+ io.WriteString(ieee, g.in)
+ s := ieee.Sum32()
+ if s != g.ieee {
+ t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, s, g.ieee)
+ }
+
+ castagnoli := New(castagnoliTab)
+ io.WriteString(castagnoli, g.in)
+ s = castagnoli.Sum32()
+ if s != g.castagnoli {
+ t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+ }
+
+ if len(g.in) > 0 {
+ // The SSE4.2 implementation of this has code to deal
+ // with misaligned data so we ensure that we test that
+ // too.
+ castagnoli = New(castagnoliTab)
+ io.WriteString(castagnoli, g.in[:1])
+ io.WriteString(castagnoli, g.in[1:])
+ s = castagnoli.Sum32()
+ if s != g.castagnoli {
+ t.Errorf("Castagnoli[misaligned](%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+ }
}
}
}
@@ -69,6 +89,7 @@ func BenchmarkCrc32KB(b *testing.B) {
}
c := NewIEEE()
b.StartTimer()
+ b.SetBytes(int64(len(data)))
for i := 0; i < b.N; i++ {
c.Write(data)
diff --git a/libgo/go/hash/fnv/fnv.go b/libgo/go/hash/fnv/fnv.go
index 9a1c6a0f2db..3ff7d7c75d7 100644
--- a/libgo/go/hash/fnv/fnv.go
+++ b/libgo/go/hash/fnv/fnv.go
@@ -11,7 +11,6 @@ import (
"encoding/binary"
"hash"
"os"
- "unsafe"
)
type (
@@ -102,31 +101,31 @@ func (s *sum64a) Write(data []byte) (int, os.Error) {
return len(data), nil
}
-func (s *sum32) Size() int { return unsafe.Sizeof(*s) }
-func (s *sum32a) Size() int { return unsafe.Sizeof(*s) }
-func (s *sum64) Size() int { return unsafe.Sizeof(*s) }
-func (s *sum64a) Size() int { return unsafe.Sizeof(*s) }
+func (s *sum32) Size() int { return 4 }
+func (s *sum32a) Size() int { return 4 }
+func (s *sum64) Size() int { return 8 }
+func (s *sum64a) Size() int { return 8 }
func (s *sum32) Sum() []byte {
- a := make([]byte, unsafe.Sizeof(*s))
+ a := make([]byte, 4)
binary.BigEndian.PutUint32(a, uint32(*s))
return a
}
func (s *sum32a) Sum() []byte {
- a := make([]byte, unsafe.Sizeof(*s))
+ a := make([]byte, 4)
binary.BigEndian.PutUint32(a, uint32(*s))
return a
}
func (s *sum64) Sum() []byte {
- a := make([]byte, unsafe.Sizeof(*s))
+ a := make([]byte, 8)
binary.BigEndian.PutUint64(a, uint64(*s))
return a
}
func (s *sum64a) Sum() []byte {
- a := make([]byte, unsafe.Sizeof(*s))
+ a := make([]byte, 8)
binary.BigEndian.PutUint64(a, uint64(*s))
return a
}
diff --git a/libgo/go/html/const.go b/libgo/go/html/const.go
new file mode 100644
index 00000000000..9078d260115
--- /dev/null
+++ b/libgo/go/html/const.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.
+
+package html
+
+// Section 11.2.3.2 of the HTML5 specification says "The following elements
+// have varying levels of special parsing rules".
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
+var isSpecialElement = map[string]bool{
+ "address": true,
+ "applet": true,
+ "area": true,
+ "article": true,
+ "aside": true,
+ "base": true,
+ "basefont": true,
+ "bgsound": true,
+ "blockquote": true,
+ "body": true,
+ "br": true,
+ "button": true,
+ "caption": true,
+ "center": true,
+ "col": true,
+ "colgroup": true,
+ "command": true,
+ "dd": true,
+ "details": true,
+ "dir": true,
+ "div": true,
+ "dl": true,
+ "dt": true,
+ "embed": true,
+ "fieldset": true,
+ "figcaption": true,
+ "figure": true,
+ "footer": true,
+ "form": true,
+ "frame": true,
+ "frameset": true,
+ "h1": true,
+ "h2": true,
+ "h3": true,
+ "h4": true,
+ "h5": true,
+ "h6": true,
+ "head": true,
+ "header": true,
+ "hgroup": true,
+ "hr": true,
+ "html": true,
+ "iframe": true,
+ "img": true,
+ "input": true,
+ "isindex": true,
+ "li": true,
+ "link": true,
+ "listing": true,
+ "marquee": true,
+ "menu": true,
+ "meta": true,
+ "nav": true,
+ "noembed": true,
+ "noframes": true,
+ "noscript": true,
+ "object": true,
+ "ol": true,
+ "p": true,
+ "param": true,
+ "plaintext": true,
+ "pre": true,
+ "script": true,
+ "section": true,
+ "select": true,
+ "style": true,
+ "summary": true,
+ "table": true,
+ "tbody": true,
+ "td": true,
+ "textarea": true,
+ "tfoot": true,
+ "th": true,
+ "thead": true,
+ "title": true,
+ "tr": true,
+ "ul": true,
+ "wbr": true,
+ "xmp": true,
+}
diff --git a/libgo/go/html/doc.go b/libgo/go/html/doc.go
index 55135c3d05f..5bc0630861a 100644
--- a/libgo/go/html/doc.go
+++ b/libgo/go/html/doc.go
@@ -4,6 +4,7 @@
/*
Package html implements an HTML5-compliant tokenizer and parser.
+INCOMPLETE.
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.
diff --git a/libgo/go/html/entity.go b/libgo/go/html/entity.go
index 1530290cb38..21263e22d8c 100644
--- a/libgo/go/html/entity.go
+++ b/libgo/go/html/entity.go
@@ -4,6 +4,9 @@
package html
+// All entities that do not end with ';' are 6 or fewer bytes long.
+const longestEntityWithoutSemicolon = 6
+
// 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.
diff --git a/libgo/go/html/entity_test.go b/libgo/go/html/entity_test.go
index a1eb4d4f013..2cf49d61d2d 100644
--- a/libgo/go/html/entity_test.go
+++ b/libgo/go/html/entity_test.go
@@ -17,6 +17,9 @@ func TestEntityLength(t *testing.T) {
if 1+len(k) < utf8.RuneLen(v) {
t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v))
}
+ if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' {
+ t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon)
+ }
}
for k, v := range entity2 {
if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) {
diff --git a/libgo/go/html/escape.go b/libgo/go/html/escape.go
index 2799f690876..0de97c5ac1b 100644
--- a/libgo/go/html/escape.go
+++ b/libgo/go/html/escape.go
@@ -53,7 +53,8 @@ var replacementTable = [...]int{
// 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) {
+// attribute should be true if parsing an attribute value.
+func unescapeEntity(b []byte, dst, src int, attribute bool) (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] == '&'.
@@ -121,12 +122,11 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
// 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' {
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
continue
}
if c != ';' {
@@ -136,11 +136,25 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
}
entityName := string(s[1:i])
- if x := entity[entityName]; x != 0 {
+ if entityName == "" {
+ // No-op.
+ } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
+ // No-op.
+ } else 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.
+ } else if x := entity2[entityName]; x[0] != 0 {
dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
+ } else if !attribute {
+ maxLen := len(entityName) - 1
+ if maxLen > longestEntityWithoutSemicolon {
+ maxLen = longestEntityWithoutSemicolon
+ }
+ for j := maxLen; j > 1; j-- {
+ if x := entity[entityName[:j]]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
+ }
+ }
}
dst1, src1 = dst+i, src+i
@@ -152,11 +166,11 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
func unescape(b []byte) []byte {
for i, c := range b {
if c == '&' {
- dst, src := unescapeEntity(b, i, i)
+ dst, src := unescapeEntity(b, i, i, false)
for src < len(b) {
c := b[src]
if c == '&' {
- dst, src = unescapeEntity(b, dst, src)
+ dst, src = unescapeEntity(b, dst, src, false)
} else {
b[dst] = c
dst, src = dst+1, src+1
diff --git a/libgo/go/html/node.go b/libgo/go/html/node.go
new file mode 100644
index 00000000000..4ecfd6ca238
--- /dev/null
+++ b/libgo/go/html/node.go
@@ -0,0 +1,147 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+// A NodeType is the type of a Node.
+type NodeType int
+
+const (
+ ErrorNode NodeType = iota
+ TextNode
+ DocumentNode
+ ElementNode
+ CommentNode
+ DoctypeNode
+ scopeMarkerNode
+)
+
+// Section 11.2.3.3 says "scope markers are inserted when entering applet
+// elements, buttons, object elements, marquees, table cells, and table
+// captions, and are used to prevent formatting from 'leaking'".
+var scopeMarker = Node{Type: scopeMarkerNode}
+
+// 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
+}
+
+// Add adds a node as a child of n.
+// It will panic if the child's parent is not nil.
+func (n *Node) Add(child *Node) {
+ if child.Parent != nil {
+ panic("html: Node.Add called for a child Node that already has a parent")
+ }
+ child.Parent = n
+ n.Child = append(n.Child, child)
+}
+
+// Remove removes a node as a child of n.
+// It will panic if the child's parent is not n.
+func (n *Node) Remove(child *Node) {
+ if child.Parent == n {
+ child.Parent = nil
+ for i, m := range n.Child {
+ if m == child {
+ copy(n.Child[i:], n.Child[i+1:])
+ j := len(n.Child) - 1
+ n.Child[j] = nil
+ n.Child = n.Child[:j]
+ return
+ }
+ }
+ }
+ panic("html: Node.Remove called for a non-child Node")
+}
+
+// reparentChildren reparents all of src's child nodes to dst.
+func reparentChildren(dst, src *Node) {
+ for _, n := range src.Child {
+ if n.Parent != src {
+ panic("html: nodes have an inconsistent parent/child relationship")
+ }
+ n.Parent = dst
+ }
+ dst.Child = append(dst.Child, src.Child...)
+ src.Child = nil
+}
+
+// clone returns a new node with the same type, data and attributes.
+// The clone has no parent and no children.
+func (n *Node) clone() *Node {
+ m := &Node{
+ Type: n.Type,
+ Data: n.Data,
+ Attr: make([]Attribute, len(n.Attr)),
+ }
+ copy(m.Attr, n.Attr)
+ return m
+}
+
+// nodeStack is a stack of nodes.
+type nodeStack []*Node
+
+// pop pops the stack. It will panic if s is empty.
+func (s *nodeStack) pop() *Node {
+ i := len(*s)
+ n := (*s)[i-1]
+ *s = (*s)[:i-1]
+ return n
+}
+
+// top returns the most recently pushed node, or nil if s is empty.
+func (s *nodeStack) top() *Node {
+ if i := len(*s); i > 0 {
+ return (*s)[i-1]
+ }
+ return nil
+}
+
+// index returns the index of the top-most occurence of n in the stack, or -1
+// if n is not present.
+func (s *nodeStack) index(n *Node) int {
+ for i := len(*s) - 1; i >= 0; i-- {
+ if (*s)[i] == n {
+ return i
+ }
+ }
+ return -1
+}
+
+// insert inserts a node at the given index.
+func (s *nodeStack) insert(i int, n *Node) {
+ (*s) = append(*s, nil)
+ copy((*s)[i+1:], (*s)[i:])
+ (*s)[i] = n
+}
+
+// remove removes a node from the stack. It is a no-op if n is not present.
+func (s *nodeStack) remove(n *Node) {
+ i := s.index(n)
+ if i == -1 {
+ return
+ }
+ copy((*s)[i:], (*s)[i+1:])
+ j := len(*s) - 1
+ (*s)[j] = nil
+ *s = (*s)[:j]
+}
+
+// forTag returns the top-most element node with the given tag.
+func (s *nodeStack) forTag(tag string) *Node {
+ for i := len(*s) - 1; i >= 0; i-- {
+ n := (*s)[i]
+ if n.Type == ElementNode && n.Data == tag {
+ return n
+ }
+ }
+ return nil
+}
diff --git a/libgo/go/html/parse.go b/libgo/go/html/parse.go
index 2ef90a87321..519ebe587b9 100644
--- a/libgo/go/html/parse.go
+++ b/libgo/go/html/parse.go
@@ -9,29 +9,6 @@ import (
"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 {
@@ -45,38 +22,23 @@ type parser struct {
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).
+ // The stack of open elements (section 11.2.3.2) and active formatting
+ // elements (section 11.2.3.3).
+ oe, afe nodeStack
+ // Element pointers (section 11.2.3.4).
head, form *Node
- // Other parsing state flags (section 10.2.3.5).
+ // Other parsing state flags (section 11.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]
+ if n := p.oe.top(); n != nil {
+ return n
}
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.
+// stopTags for use in popUntil. These come from section 11.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"}
@@ -102,11 +64,11 @@ var (
// 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 i := len(p.oe) - 1; i >= 0; i-- {
+ tag := p.oe[i].Data
for _, t := range matchTags {
if t == tag {
- p.stack = p.stack[:i]
+ p.oe = p.oe[:i]
return true
}
}
@@ -119,20 +81,24 @@ func (p *parser) popUntil(stopTags []string, matchTags ...string) bool {
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).
+// addChild adds a child node n to the top element, and pushes n onto the stack
+// of open elements if it is an element node.
func (p *parser) addChild(n *Node) {
- m := p.top()
- m.Child = append(m.Child, n)
+ p.top().Add(n)
if n.Type == ElementNode {
- p.push(n)
+ p.oe = append(p.oe, n)
}
}
-// addText calls addChild with a text node.
+// addText adds text to the preceding node if it is a text node, or else it
+// calls addChild with a new 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.
+ t := p.top()
+ if i := len(t.Child); i > 0 && t.Child[i-1].Type == TextNode {
+ t.Child[i-1].Data += text
+ return
+ }
p.addChild(&Node{
Type: TextNode,
Data: text,
@@ -148,15 +114,50 @@ func (p *parser) addElement(tag string, attr []Attribute) {
})
}
-// Section 10.2.3.3.
+// Section 11.2.3.3.
func (p *parser) addFormattingElement(tag string, attr []Attribute) {
p.addElement(tag, attr)
+ p.afe = append(p.afe, p.top())
// TODO.
}
-// Section 10.2.3.3.
+// Section 11.2.3.3.
+func (p *parser) clearActiveFormattingElements() {
+ for {
+ n := p.afe.pop()
+ if len(p.afe) == 0 || n.Type == scopeMarkerNode {
+ return
+ }
+ }
+}
+
+// Section 11.2.3.3.
func (p *parser) reconstructActiveFormattingElements() {
- // TODO.
+ n := p.afe.top()
+ if n == nil {
+ return
+ }
+ if n.Type == scopeMarkerNode || p.oe.index(n) != -1 {
+ return
+ }
+ i := len(p.afe) - 1
+ for n.Type != scopeMarkerNode && p.oe.index(n) == -1 {
+ if i == 0 {
+ i = -1
+ break
+ }
+ i--
+ n = p.afe[i]
+ }
+ for {
+ i++
+ n = p.afe[i]
+ p.addChild(n.clone())
+ p.afe[i] = n
+ if i == len(p.afe)-1 {
+ break
+ }
+ }
}
// read reads the next token. This is usually from the tokenizer, but it may
@@ -180,12 +181,12 @@ func (p *parser) read() os.Error {
return nil
}
-// Section 10.2.4.
+// Section 11.2.4.
func (p *parser) acknowledgeSelfClosingTag() {
p.hasSelfClosingToken = false
}
-// An insertion mode (section 10.2.3.1) is the state transition function from
+// An insertion mode (section 11.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
@@ -194,7 +195,7 @@ 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".
+// Section 11.2.3.1, "using the rules for".
func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, bool) {
im, consumed := delegate(p)
if im != delegate {
@@ -203,13 +204,21 @@ func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, b
return actual, consumed
}
-// Section 10.2.5.4.
+// Section 11.2.5.4.1.
func initialIM(p *parser) (insertionMode, bool) {
- // TODO: check p.tok for DOCTYPE.
+ if p.tok.Type == DoctypeToken {
+ p.addChild(&Node{
+ Type: DoctypeNode,
+ Data: p.tok.Data,
+ })
+ return beforeHTMLIM, true
+ }
+ // TODO: set "quirks mode"? It's defined in the DOM spec instead of HTML5 proper,
+ // and so switching on "quirks mode" might belong in a different package.
return beforeHTMLIM, false
}
-// Section 10.2.5.5.
+// Section 11.2.5.4.2.
func beforeHTMLIM(p *parser) (insertionMode, bool) {
var (
add bool
@@ -243,7 +252,7 @@ func beforeHTMLIM(p *parser) (insertionMode, bool) {
return beforeHeadIM, !implied
}
-// Section 10.2.5.6.
+// Section 11.2.5.4.3.
func beforeHeadIM(p *parser) (insertionMode, bool) {
var (
add bool
@@ -280,7 +289,7 @@ func beforeHeadIM(p *parser) (insertionMode, bool) {
return inHeadIM, !implied
}
-// Section 10.2.5.7.
+// Section 11.2.5.4.4.
func inHeadIM(p *parser) (insertionMode, bool) {
var (
pop bool
@@ -305,7 +314,7 @@ func inHeadIM(p *parser) (insertionMode, bool) {
// TODO.
}
if pop || implied {
- n := p.pop()
+ n := p.oe.pop()
if n.Data != "head" {
panic("html: bad parser state")
}
@@ -314,7 +323,7 @@ func inHeadIM(p *parser) (insertionMode, bool) {
return inHeadIM, !implied
}
-// Section 10.2.5.9.
+// Section 11.2.5.4.6.
func afterHeadIM(p *parser) (insertionMode, bool) {
var (
add bool
@@ -354,17 +363,18 @@ func afterHeadIM(p *parser) (insertionMode, bool) {
return inBodyIM, !implied
}
-// Section 10.2.5.10.
+// Section 11.2.5.4.7.
func inBodyIM(p *parser) (insertionMode, bool) {
var endP bool
switch p.tok.Type {
case TextToken:
+ p.reconstructActiveFormattingElements()
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.
+ // TODO: Do the proper "does the stack of open elements has a p element in button scope" algorithm in section 11.2.3.2.
n := p.top()
if n.Type == ElementNode && n.Data == "p" {
endP = true
@@ -375,16 +385,24 @@ func inBodyIM(p *parser) (insertionMode, bool) {
// TODO: auto-insert </p> if necessary.
switch n := p.top(); n.Data {
case "h1", "h2", "h3", "h4", "h5", "h6":
- p.pop()
+ p.oe.pop()
}
p.addElement(p.tok.Data, p.tok.Attr)
+ case "a":
+ if n := p.afe.forTag("a"); n != nil {
+ p.inBodyEndTagFormatting("a")
+ p.oe.remove(n)
+ p.afe.remove(n)
+ }
+ p.reconstructActiveFormattingElements()
+ p.addFormattingElement(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.oe.pop()
p.acknowledgeSelfClosingTag()
p.framesetOK = false
case "table":
@@ -395,11 +413,12 @@ func inBodyIM(p *parser) (insertionMode, bool) {
case "hr":
// TODO: auto-insert </p> if necessary.
p.addElement(p.tok.Data, p.tok.Attr)
- p.pop()
+ p.oe.pop()
p.acknowledgeSelfClosingTag()
p.framesetOK = false
default:
// TODO.
+ p.addElement(p.tok.Data, p.tok.Attr)
}
case EndTagToken:
switch p.tok.Data {
@@ -407,18 +426,17 @@ func inBodyIM(p *parser) (insertionMode, bool) {
// 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
+ p.inBodyEndTagFormatting(p.tok.Data)
+ default:
+ // TODO: any other end tag
if p.tok.Data == p.top().Data {
- p.pop()
+ p.oe.pop()
}
- default:
- // TODO.
}
}
if endP {
// TODO: do the proper algorithm.
- n := p.pop()
+ n := p.oe.pop()
if n.Type != ElementNode || n.Data != "p" {
panic("unreachable")
}
@@ -426,7 +444,123 @@ func inBodyIM(p *parser) (insertionMode, bool) {
return inBodyIM, !endP
}
-// Section 10.2.5.12.
+func (p *parser) inBodyEndTagFormatting(tag string) {
+ // This is the "adoption agency" algorithm, described at
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
+
+ // TODO: this is a fairly literal line-by-line translation of that algorithm.
+ // Once the code successfully parses the comprehensive test suite, we should
+ // refactor this code to be more idiomatic.
+
+ // Steps 1-3. The outer loop.
+ for i := 0; i < 8; i++ {
+ // Step 4. Find the formatting element.
+ var formattingElement *Node
+ for j := len(p.afe) - 1; j >= 0; j-- {
+ if p.afe[j].Type == scopeMarkerNode {
+ break
+ }
+ if p.afe[j].Data == tag {
+ formattingElement = p.afe[j]
+ break
+ }
+ }
+ if formattingElement == nil {
+ return
+ }
+ feIndex := p.oe.index(formattingElement)
+ if feIndex == -1 {
+ p.afe.remove(formattingElement)
+ return
+ }
+
+ // Steps 5-6. Find the furthest block.
+ var furthestBlock *Node
+ for _, e := range p.oe[feIndex:] {
+ if isSpecialElement[e.Data] {
+ furthestBlock = e
+ break
+ }
+ }
+ if furthestBlock == nil {
+ e := p.oe.pop()
+ for e != formattingElement {
+ e = p.oe.pop()
+ }
+ p.afe.remove(e)
+ return
+ }
+
+ // Steps 7-8. Find the common ancestor and bookmark node.
+ commonAncestor := p.oe[feIndex-1]
+ bookmark := p.afe.index(formattingElement)
+
+ // Step 9. The inner loop. Find the lastNode to reparent.
+ lastNode := furthestBlock
+ node := furthestBlock
+ x := p.oe.index(node)
+ // Steps 9.1-9.3.
+ for j := 0; j < 3; j++ {
+ // Step 9.4.
+ x--
+ node = p.oe[x]
+ // Step 9.5.
+ if p.afe.index(node) == -1 {
+ p.oe.remove(node)
+ continue
+ }
+ // Step 9.6.
+ if node == formattingElement {
+ break
+ }
+ // Step 9.7.
+ clone := node.clone()
+ p.afe[p.afe.index(node)] = clone
+ p.oe[p.oe.index(node)] = clone
+ node = clone
+ // Step 9.8.
+ if lastNode == furthestBlock {
+ bookmark = p.afe.index(node) + 1
+ }
+ // Step 9.9.
+ if lastNode.Parent != nil {
+ lastNode.Parent.Remove(lastNode)
+ }
+ node.Add(lastNode)
+ // Step 9.10.
+ lastNode = node
+ }
+
+ // Step 10. Reparent lastNode to the common ancestor,
+ // or for misnested table nodes, to the foster parent.
+ if lastNode.Parent != nil {
+ lastNode.Parent.Remove(lastNode)
+ }
+ switch commonAncestor.Data {
+ case "table", "tbody", "tfoot", "thead", "tr":
+ // TODO: fix up misnested table nodes; find the foster parent.
+ fallthrough
+ default:
+ commonAncestor.Add(lastNode)
+ }
+
+ // Steps 11-13. Reparent nodes from the furthest block's children
+ // to a clone of the formatting element.
+ clone := formattingElement.clone()
+ reparentChildren(clone, furthestBlock)
+ furthestBlock.Add(clone)
+
+ // Step 14. Fix up the list of active formatting elements.
+ p.afe.remove(formattingElement)
+ p.afe.insert(bookmark, clone)
+
+ // Step 15. Fix up the stack of open elements.
+ p.oe.remove(formattingElement)
+ p.oe.insert(p.oe.index(furthestBlock)+1, clone)
+ }
+}
+
+// Section 11.2.5.4.9.
func inTableIM(p *parser) (insertionMode, bool) {
var (
add bool
@@ -457,7 +591,7 @@ func inTableIM(p *parser) (insertionMode, bool) {
switch p.tok.Data {
case "table":
if p.popUntil(tableScopeStopTags, "table") {
- // TODO: "reset the insertion mode appropriately" as per 10.2.3.1.
+ // TODO: "reset the insertion mode appropriately" as per 11.2.3.1.
return inBodyIM, false
}
// Ignore the token.
@@ -476,7 +610,7 @@ func inTableIM(p *parser) (insertionMode, bool) {
return inTableIM, true
}
-// Section 10.2.5.16.
+// Section 11.2.5.4.13.
func inTableBodyIM(p *parser) (insertionMode, bool) {
var (
add bool
@@ -524,7 +658,7 @@ func inTableBodyIM(p *parser) (insertionMode, bool) {
return useTheRulesFor(p, inTableBodyIM, inTableIM)
}
-// Section 10.2.5.17.
+// Section 11.2.5.4.14.
func inRowIM(p *parser) (insertionMode, bool) {
switch p.tok.Type {
case ErrorToken:
@@ -536,7 +670,7 @@ func inRowIM(p *parser) (insertionMode, bool) {
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.
+ p.afe = append(p.afe, &scopeMarker)
return inCellIM, true
default:
// TODO.
@@ -563,7 +697,7 @@ func inRowIM(p *parser) (insertionMode, bool) {
return useTheRulesFor(p, inRowIM, inTableIM)
}
-// Section 10.2.5.18.
+// Section 11.2.5.4.15.
func inCellIM(p *parser) (insertionMode, bool) {
var (
closeTheCellAndReprocess bool
@@ -588,14 +722,14 @@ func inCellIM(p *parser) (insertionMode, bool) {
}
if closeTheCellAndReprocess {
if p.popUntil(tableScopeStopTags, "td") || p.popUntil(tableScopeStopTags, "th") {
- // TODO: clear the list of active formatting elements up to the last marker.
+ p.clearActiveFormattingElements()
return inRowIM, false
}
}
return useTheRulesFor(p, inCellIM, inBodyIM)
}
-// Section 10.2.5.22.
+// Section 11.2.5.4.18.
func afterBodyIM(p *parser) (insertionMode, bool) {
switch p.tok.Type {
case ErrorToken:
@@ -616,7 +750,7 @@ func afterBodyIM(p *parser) (insertionMode, bool) {
return afterBodyIM, true
}
-// Section 10.2.5.25.
+// Section 11.2.5.4.21.
func afterAfterBodyIM(p *parser) (insertionMode, bool) {
switch p.tok.Type {
case ErrorToken:
diff --git a/libgo/go/html/parse_test.go b/libgo/go/html/parse_test.go
index 3fa35d5dbe4..7d918d25086 100644
--- a/libgo/go/html/parse_test.go
+++ b/libgo/go/html/parse_test.go
@@ -85,6 +85,10 @@ func dumpLevel(w io.Writer, n *Node, level int) os.Error {
fmt.Fprintf(w, "%q", EscapeString(n.Data))
case CommentNode:
return os.NewError("COMMENT")
+ case DoctypeNode:
+ fmt.Fprintf(w, "<!DOCTYPE %s>", EscapeString(n.Data))
+ case scopeMarkerNode:
+ return os.NewError("unexpected scopeMarkerNode")
default:
return os.NewError("unknown node type")
}
@@ -119,7 +123,7 @@ func TestParser(t *testing.T) {
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++ {
+ for i := 0; i < 25; i++ {
// Parse the #data section.
b, err := ioutil.ReadAll(<-rc)
if err != nil {
diff --git a/libgo/go/html/testdata/webkit/comments01.dat b/libgo/go/html/testdata/webkit/comments01.dat
index 388d9528726..44f18768300 100644
--- a/libgo/go/html/testdata/webkit/comments01.dat
+++ b/libgo/go/html/testdata/webkit/comments01.dat
@@ -28,8 +28,7 @@ FOO<!-- BAR -- >BAZ
| <head>
| <body>
| "FOO"
-| <!-- BAR -- -->
-| "BAZ"
+| <!-- BAR -- >BAZ -->
#data
FOO<!-- BAR -- <QUX> -- MUX -->BAZ
@@ -61,8 +60,7 @@ FOO<!-- BAR -- <QUX> -- MUX -- >BAZ
| <head>
| <body>
| "FOO"
-| <!-- BAR -- <QUX> -- MUX -- -->
-| "BAZ"
+| <!-- BAR -- <QUX> -- MUX -- >BAZ -->
#data
FOO<!---->BAZ
@@ -124,3 +122,14 @@ FOO<!-->BAZ
| <html>
| <head>
| <body>
+
+#data
+FOO<!----->BAZ
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "FOO"
+| <!-- - -->
+| "BAZ"
diff --git a/libgo/go/html/testdata/webkit/doctype01.dat b/libgo/go/html/testdata/webkit/doctype01.dat
index 575129c1466..ae457328a45 100644
--- a/libgo/go/html/testdata/webkit/doctype01.dat
+++ b/libgo/go/html/testdata/webkit/doctype01.dat
@@ -132,7 +132,7 @@
<!DOCTYPE potato SYSTEM 'taco"'>Hello
#errors
#document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "" "taco"">
| <html>
| <head>
| <body>
@@ -142,7 +142,7 @@
<!DOCTYPE potato SYSTEM "taco">Hello
#errors
#document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "" "taco">
| <html>
| <head>
| <body>
@@ -152,7 +152,7 @@
<!DOCTYPE potato SYSTEM "tai'co">Hello
#errors
#document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "" "tai'co">
| <html>
| <head>
| <body>
@@ -222,7 +222,7 @@
<!DOCTYPE potato PUBLIC "go'of">Hello
#errors
#document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "go'of" "">
| <html>
| <head>
| <body>
@@ -232,7 +232,7 @@
<!DOCTYPE potato PUBLIC 'go'of'>Hello
#errors
#document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "go" "">
| <html>
| <head>
| <body>
@@ -242,7 +242,7 @@
<!DOCTYPE potato PUBLIC 'go:hh of' >Hello
#errors
#document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "go:hh of" "">
| <html>
| <head>
| <body>
@@ -252,7 +252,7 @@
<!DOCTYPE potato PUBLIC "W3C-//dfdf" SYSTEM ggg>Hello
#errors
#document
-| <!DOCTYPE potato>
+| <!DOCTYPE potato "W3C-//dfdf" "">
| <html>
| <head>
| <body>
@@ -263,7 +263,7 @@
"http://www.w3.org/TR/html4/strict.dtd">Hello
#errors
#document
-| <!DOCTYPE html>
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
| <html>
| <head>
| <body>
@@ -284,7 +284,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
#errors
#document
-| <!DOCTYPE html>
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
| <html>
| <head>
| <body>
@@ -294,7 +294,7 @@
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
#errors
#document
-| <!DOCTYPE html>
+| <!DOCTYPE html "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
| <html>
| <head>
| <body>
@@ -309,8 +309,7 @@
| <html>
| <head>
| <body>
-| "
-]>"
+| "]>"
#data
<!DOCTYPE html PUBLIC
@@ -318,7 +317,7 @@
"http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
#errors
#document
-| <!DOCTYPE html>
+| <!DOCTYPE html "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
| <html>
| <head>
| <body>
@@ -327,9 +326,45 @@
<!DOCTYPE HTML SYSTEM "http://www.w3.org/DTD/HTML4-strict.dtd"><body><b>Mine!</b></body>
#errors
#document
-| <!DOCTYPE html>
+| <!DOCTYPE html "" "http://www.w3.org/DTD/HTML4-strict.dtd">
| <html>
| <head>
| <body>
| <b>
| "Mine!"
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01//EN"'http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
+
+#data
+<!DOCTYPE HTML PUBLIC'-//W3C//DTD HTML 4.01//EN''http://www.w3.org/TR/html4/strict.dtd'>
+#errors
+#document
+| <!DOCTYPE html "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+| <html>
+| <head>
+| <body>
diff --git a/libgo/go/html/testdata/webkit/dom2string.js b/libgo/go/html/testdata/webkit/dom2string.js
deleted file mode 100644
index 45897fda4d8..00000000000
--- a/libgo/go/html/testdata/webkit/dom2string.js
+++ /dev/null
@@ -1,135 +0,0 @@
-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
index 926642e2e22..c8073b7810b 100644
--- a/libgo/go/html/testdata/webkit/entities01.dat
+++ b/libgo/go/html/testdata/webkit/entities01.dat
@@ -189,15 +189,6 @@ FOO&#x0000;ZOO
| "FOO�ZOO"
#data
-FOO&#x000D;ZOO
-#errors
-#document
-| <html>
-| <head>
-| <body>
-| "FOO ZOO"
-
-#data
FOO&#x0078;ZOO
#errors
#document
diff --git a/libgo/go/html/testdata/webkit/entities02.dat b/libgo/go/html/testdata/webkit/entities02.dat
index 0b4dd668199..e2fb42a078b 100644
--- a/libgo/go/html/testdata/webkit/entities02.dat
+++ b/libgo/go/html/testdata/webkit/entities02.dat
@@ -127,3 +127,123 @@
| <body>
| <div>
| bar="ZZ>"
+
+#data
+<div bar="ZZ&pound_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&prod_id=23"
+
+#data
+<div bar="ZZ&pound;_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ£_id=23"
+
+#data
+<div bar="ZZ&prod;_id=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ∏_id=23"
+
+#data
+<div bar="ZZ&pound=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&pound=23"
+
+#data
+<div bar="ZZ&prod=23"></div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| bar="ZZ&prod=23"
+
+#data
+<div>ZZ&pound_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£_id=23"
+
+#data
+<div>ZZ&prod_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ&prod_id=23"
+
+#data
+<div>ZZ&pound;_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£_id=23"
+
+#data
+<div>ZZ&prod;_id=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ∏_id=23"
+
+#data
+<div>ZZ&pound=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ£=23"
+
+#data
+<div>ZZ&prod=23</div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| "ZZ&prod=23"
diff --git a/libgo/go/html/testdata/webkit/tests1.dat b/libgo/go/html/testdata/webkit/tests1.dat
index ad58d314fd6..cbf8bdda638 100644
--- a/libgo/go/html/testdata/webkit/tests1.dat
+++ b/libgo/go/html/testdata/webkit/tests1.dat
@@ -259,7 +259,7 @@ Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency
| "Z"
#data
-<b><button></b></button></b>
+<b><button>foo</b>bar
#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.
@@ -268,7 +268,23 @@ Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency
| <head>
| <body>
| <b>
+| <button>
+| <b>
+| "foo"
+| "bar"
+
+#data
+<!DOCTYPE html><span><button>foo</span>bar
+#errors
+39: End tag “span” seen but there were unclosed elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <span>
| <button>
+| "foobar"
#data
<p><b><div><marquee></p></b></div>X
@@ -818,32 +834,6 @@ Line: 1 Col: 22 Expected closing tag. Unexpected end of file.
| "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.
@@ -1246,6 +1236,18 @@ Line: 1 Col: 49 Unexpected end tag (code). Ignored.
| <strike>
#data
+<!DOCTYPE html><spacer>foo
+#errors
+26: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <spacer>
+| "foo"
+
+#data
<title><meta></title><link><title><meta></title>
#errors
Line: 1 Col: 7 Unexpected start tag (title). Expected DOCTYPE.
@@ -1474,7 +1476,8 @@ Line: 1 Col: 15 End tag (b) violates step 1, paragraph 1 of the adoption agency
| <head>
| <body>
| <b>
-| <button>
+| <button>
+| <b>
#data
<p><b><div><marquee></p></b></div>
diff --git a/libgo/go/html/testdata/webkit/tests10.dat b/libgo/go/html/testdata/webkit/tests10.dat
index 877c9a3d73a..4f8df86f208 100644
--- a/libgo/go/html/testdata/webkit/tests10.dat
+++ b/libgo/go/html/testdata/webkit/tests10.dat
@@ -9,6 +9,18 @@
| <svg svg>
#data
+<!DOCTYPE html><svg></svg><![CDATA[a]]>
+#errors
+29: Bogus comment
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <!-- [CDATA[a]] -->
+
+#data
<!DOCTYPE html><body><svg></svg>
#errors
#document
@@ -428,3 +440,360 @@
| xlink href="foo"
| xml lang="en"
| "bar"
+
+#data
+<svg></path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+
+#data
+<div><svg></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| "a"
+
+#data
+<div><svg><path></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| "a"
+
+#data
+<div><svg><path></svg><path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <path>
+
+#data
+<div><svg><path><foreignObject><math></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <math math>
+| "a"
+
+#data
+<div><svg><path><foreignObject><p></div>a
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <p>
+| "a"
+
+#data
+<!DOCTYPE html><svg><desc><div><svg><ul>a
+#errors
+40: HTML start tag “ul” in a foreign namespace context.
+41: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg desc>
+| <div>
+| <svg svg>
+| <ul>
+| "a"
+
+#data
+<!DOCTYPE html><svg><desc><svg><ul>a
+#errors
+35: HTML start tag “ul” in a foreign namespace context.
+36: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg desc>
+| <svg svg>
+| <ul>
+| "a"
+
+#data
+<!DOCTYPE html><p><svg><desc><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <svg svg>
+| <svg desc>
+| <p>
+
+#data
+<!DOCTYPE html><p><svg><title><p>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <p>
+| <svg svg>
+| <svg title>
+| <p>
+
+#data
+<div><svg><path><foreignObject><p></foreignObject><p>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <svg svg>
+| <svg path>
+| <svg foreignObject>
+| <p>
+| <p>
+
+#data
+<math><mi><div><object><div><span></span></div></object></div></mi><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <div>
+| <object>
+| <div>
+| <span>
+| <math mi>
+
+#data
+<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <div>
+| <math mi>
+
+#data
+<svg><script></script><path>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg script>
+| <svg path>
+
+#data
+<table><svg></svg><tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <table>
+| <tbody>
+| <tr>
+
+#data
+<math><mi><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <math mglyph>
+
+#data
+<math><mi><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+| <math malignmark>
+
+#data
+<math><mo><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mo>
+| <math mglyph>
+
+#data
+<math><mo><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mo>
+| <math malignmark>
+
+#data
+<math><mn><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| <math mglyph>
+
+#data
+<math><mn><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mn>
+| <math malignmark>
+
+#data
+<math><ms><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math ms>
+| <math mglyph>
+
+#data
+<math><ms><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math ms>
+| <math malignmark>
+
+#data
+<math><mtext><mglyph>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <math mglyph>
+
+#data
+<math><mtext><malignmark>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mtext>
+| <math malignmark>
+
+#data
+<math><annotation-xml><svg></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><div><math><mi></mi></math><span></span></div></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <svg foreignObject>
+| <div>
+| <math math>
+| <math mi>
+| <span>
+| <svg path>
+| <math mi>
+
+#data
+<math><annotation-xml><svg><foreignObject><math><mi><svg></svg></mi><mo></mo></math><span></span></foreignObject><path></path></svg></annotation-xml><mi>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <svg foreignObject>
+| <math math>
+| <math mi>
+| <svg svg>
+| <math mo>
+| <span>
+| <svg path>
+| <math mi>
diff --git a/libgo/go/html/testdata/webkit/tests13.dat b/libgo/go/html/testdata/webkit/tests13.dat
deleted file mode 100644
index d180e8e90f2..00000000000
--- a/libgo/go/html/testdata/webkit/tests13.dat
+++ /dev/null
@@ -1,9 +0,0 @@
-<!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
index 72f8015f6e0..b8713f88582 100644
--- a/libgo/go/html/testdata/webkit/tests14.dat
+++ b/libgo/go/html/testdata/webkit/tests14.dat
@@ -71,4 +71,4 @@
| <html>
| <head>
| <body>
-| 789="012" \ No newline at end of file
+| 789="012"
diff --git a/libgo/go/html/testdata/webkit/tests15.dat b/libgo/go/html/testdata/webkit/tests15.dat
index 7f016cae386..6ce1c0d1663 100644
--- a/libgo/go/html/testdata/webkit/tests15.dat
+++ b/libgo/go/html/testdata/webkit/tests15.dat
@@ -205,4 +205,4 @@ XXX: These errors are wrong, please fix me!
| <html>
| <head>
| <body>
-| <object> \ No newline at end of file
+| <object>
diff --git a/libgo/go/html/testdata/webkit/tests2.dat b/libgo/go/html/testdata/webkit/tests2.dat
index d33996e0ccb..60d85922162 100644
--- a/libgo/go/html/testdata/webkit/tests2.dat
+++ b/libgo/go/html/testdata/webkit/tests2.dat
@@ -461,6 +461,19 @@ Line: 1 Col: 51 Expected closing tag. Unexpected end of file.
| <optgroup>
#data
+<!DOCTYPE html><datalist><option>foo</datalist>bar
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <datalist>
+| <option>
+| "foo"
+| "bar"
+
+#data
<!DOCTYPE html><font><input><input></font>
#errors
#document
@@ -515,7 +528,7 @@ Line: 1 Col: 23 Unexpected start tag isindex. Don't use it!
| <form>
| <hr>
| <label>
-| "This is a searchable index. Insert your search keywords here: "
+| "This is a searchable index. Enter search keywords: "
| <input>
| name="isindex"
| test="x"
@@ -736,3 +749,15 @@ Line: 1 Col: 35 Unexpected character in comment found.
| ">"
| <!-- <!--x -->
| "-->"
+
+#data
+<!doctype html><div><form></form><div></div></div>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <div>
+| <form>
+| <div>
diff --git a/libgo/go/html/testdata/webkit/tests3.dat b/libgo/go/html/testdata/webkit/tests3.dat
index b0781a87e31..38dc501be35 100644
--- a/libgo/go/html/testdata/webkit/tests3.dat
+++ b/libgo/go/html/testdata/webkit/tests3.dat
@@ -144,6 +144,18 @@ Line: 2 Col: 7 End tag (pre) seen too early. Expected other end tag.
y"
#data
+<!DOCTYPE html><pre>&#x0a;&#x0a;A</pre>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <pre>
+| "
+A"
+
+#data
<!DOCTYPE html><HTML><META><HEAD></HEAD></HTML>
#errors
Line: 1 Col: 33 Unexpected start tag head in existing head. Ignored.
diff --git a/libgo/go/html/testdata/webkit/tests6.dat b/libgo/go/html/testdata/webkit/tests6.dat
index 2fb79967f1e..f28ece4fb00 100644
--- a/libgo/go/html/testdata/webkit/tests6.dat
+++ b/libgo/go/html/testdata/webkit/tests6.dat
@@ -631,6 +631,16 @@ Line: 1 Col: 17 Unexpected start tag (frameset).
| <frameset>
#data
+<track><frameset></frameset>
+#errors
+Line: 1 Col: 7 Unexpected start tag (track). 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>”.
diff --git a/libgo/go/html/testdata/webkit/tests9.dat b/libgo/go/html/testdata/webkit/tests9.dat
index 2b715f83dd4..554e27aecf6 100644
--- a/libgo/go/html/testdata/webkit/tests9.dat
+++ b/libgo/go/html/testdata/webkit/tests9.dat
@@ -19,6 +19,33 @@
| <math math>
#data
+<!DOCTYPE html><math><mi>
+#errors
+25: End of file in a foreign namespace context.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mi>
+
+#data
+<!DOCTYPE html><math><annotation-xml><svg><u>
+#errors
+45: HTML start tag “u” in a foreign namespace context.
+45: End of file seen and there were open elements.
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math annotation-xml>
+| <svg svg>
+| <u>
+
+#data
<!DOCTYPE html><body><select><math></math></select>
#errors
Line: 1 Col: 35 Unexpected start tag token (math) in the select phase. Ignored.
diff --git a/libgo/go/html/testdata/webkit/webkit01.dat b/libgo/go/html/testdata/webkit/webkit01.dat
index 544da9e8a21..4101b216e18 100644
--- a/libgo/go/html/testdata/webkit/webkit01.dat
+++ b/libgo/go/html/testdata/webkit/webkit01.dat
@@ -129,35 +129,6 @@ console.log("FOO<span>BAR</span>BAZ");
| <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
@@ -186,8 +157,7 @@ console.log("FOO<span>BAR</span>BAZ");
| <head>
| <body>
| <p>
-| "Test"
-| "Test2"
+| "TestTest2"
#data
<rdar://problem/6869687>
@@ -209,3 +179,431 @@ console.log("FOO<span>BAR</span>BAZ");
| <body>
| <a>
| "test< /A>"
+
+#data
+&lt;
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "<"
+
+#data
+<body foo='bar'><body foo='baz' yo='mama'>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| foo="bar"
+| yo="mama"
+
+#data
+<body></br foo="bar"></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<bdy><br foo="bar"></body>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <bdy>
+| <br>
+| foo="bar"
+
+#data
+<body></body></br foo="bar">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <br>
+
+#data
+<bdy></body><br foo="bar">
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <bdy>
+| <br>
+| foo="bar"
+
+#data
+<html><body></body></html><!-- Hi there -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <!-- Hi there -->
+
+#data
+<html><body></body></html>x<!-- Hi there -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></html><!-- Again -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+| <!-- Again -->
+
+#data
+<html><body></body></html>x<!-- Hi there --></body></html><!-- Again -->
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| "x"
+| <!-- Hi there -->
+| <!-- Again -->
+
+#data
+<html><body><ruby><div><rp>xx</rp></div></ruby></body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <rp>
+| "xx"
+
+#data
+<html><body><ruby><div><rt>xx</rt></div></ruby></body></html>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ruby>
+| <div>
+| <rt>
+| "xx"
+
+#data
+<html><frameset><!--1--><noframes>A</noframes><!--2--></frameset><!--3--><noframes>B</noframes><!--4--></html><!--5--><noframes>C</noframes><!--6-->
+#errors
+#document
+| <html>
+| <head>
+| <frameset>
+| <!-- 1 -->
+| <noframes>
+| "A"
+| <!-- 2 -->
+| <!-- 3 -->
+| <noframes>
+| "B"
+| <!-- 4 -->
+| <noframes>
+| "C"
+| <!-- 5 -->
+| <!-- 6 -->
+
+#data
+<select><option>A<select><option>B<select><option>C<select><option>D<select><option>E<select><option>F<select><option>G<select>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <select>
+| <option>
+| "A"
+| <option>
+| "B"
+| <select>
+| <option>
+| "C"
+| <option>
+| "D"
+| <select>
+| <option>
+| "E"
+| <option>
+| "F"
+| <select>
+| <option>
+| "G"
+
+#data
+<dd><dd><dt><dt><dd><li><li>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <dd>
+| <dd>
+| <dt>
+| <dt>
+| <dd>
+| <li>
+| <li>
+
+#data
+<div><b></div><div><nobr>a<nobr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <div>
+| <b>
+| <div>
+| <b>
+| <nobr>
+| "a"
+| <nobr>
+
+#data
+<head></head>
+<body></body>
+#errors
+#document
+| <html>
+| <head>
+| "
+"
+| <body>
+
+#data
+<head></head> <style></style>ddd
+#errors
+#document
+| <html>
+| <head>
+| <style>
+| " "
+| <body>
+| "ddd"
+
+#data
+<kbd><table></kbd><col><select><tr>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <kbd>
+| <select>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+
+#data
+<kbd><table></kbd><col><select><tr></table><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <kbd>
+| <select>
+| <table>
+| <colgroup>
+| <col>
+| <tbody>
+| <tr>
+| <div>
+
+#data
+<a><li><style></style><title></title></a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <li>
+| <a>
+| <style>
+| <title>
+
+#data
+<font></p><p><meta><title></title></font>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <font>
+| <p>
+| <p>
+| <font>
+| <meta>
+| <title>
+
+#data
+<a><center><title></title><a>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <a>
+| <center>
+| <a>
+| <title>
+| <a>
+
+#data
+<svg><title><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <div>
+
+#data
+<svg><title><rect><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <rect>
+| <div>
+
+#data
+<svg><title><svg><div>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg title>
+| <svg svg>
+| <div>
+
+#data
+<img <="" FAIL>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <img>
+| <=""
+| fail=""
+
+#data
+<ul><li><div id='foo'/>A</li><li>B<div>C</div></li></ul>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <ul>
+| <li>
+| <div>
+| id="foo"
+| "A"
+| <li>
+| "B"
+| <div>
+| "C"
+
+#data
+<svg><em><desc></em>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <em>
+| <desc>
+
+#data
+<table><tr><td><svg><desc><td></desc><circle>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <table>
+| <tbody>
+| <tr>
+| <td>
+| <svg svg>
+| <svg desc>
+| <svg circle>
+
+#data
+<svg><tfoot></mi><td>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <svg svg>
+| <svg tfoot>
+| <svg td>
+
+#data
+<math><mrow><mrow><mn>1</mn></mrow><mi>a</mi></mrow></math>
+#errors
+#document
+| <html>
+| <head>
+| <body>
+| <math math>
+| <math mrow>
+| <math mrow>
+| <math mn>
+| "1"
+| <math mi>
+| "a"
+
+#data
+<!doctype html><input type="hidden"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <frameset>
+
+#data
+<!doctype html><input type="button"><frameset>
+#errors
+#document
+| <!DOCTYPE html>
+| <html>
+| <head>
+| <body>
+| <input>
+| type="button"
diff --git a/libgo/go/html/token.go b/libgo/go/html/token.go
index ad03241ed92..d266b3a300b 100644
--- a/libgo/go/html/token.go
+++ b/libgo/go/html/token.go
@@ -27,6 +27,8 @@ const (
SelfClosingTagToken
// A CommentToken looks like <!--x-->.
CommentToken
+ // A DoctypeToken looks like <!DOCTYPE x>
+ DoctypeToken
)
// String returns a string representation of the TokenType.
@@ -44,6 +46,8 @@ func (t TokenType) String() string {
return "SelfClosingTag"
case CommentToken:
return "Comment"
+ case DoctypeToken:
+ return "Doctype"
}
return "Invalid(" + strconv.Itoa(int(t)) + ")"
}
@@ -56,9 +60,9 @@ type Attribute struct {
}
// A Token consists of a TokenType and some Data (tag name for start and end
-// tags, content for text and comments). A tag Token may also contain a slice
-// of Attributes. Data is unescaped for all Tokens (it looks like "a<b" rather
-// than "a&lt;b").
+// tags, content for text, comments and doctypes). A tag Token may also contain
+// a slice of Attributes. Data is unescaped for all Tokens (it looks like "a<b"
+// rather than "a&lt;b").
type Token struct {
Type TokenType
Data string
@@ -97,6 +101,8 @@ func (t Token) String() string {
return "<" + t.tagString() + "/>"
case CommentToken:
return "<!--" + EscapeString(t.Data) + "-->"
+ case DoctypeToken:
+ return "<!DOCTYPE " + EscapeString(t.Data) + ">"
}
return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
}
@@ -109,9 +115,15 @@ 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
+ // tt is the TokenType of the most recently read token.
+ tt TokenType
+ // err is the first error encountered during tokenization. It is possible
+ // for tt != Error && err != nil to hold: this means that Next returned a
+ // valid token but the subsequent Next call will return an error token.
+ // For example, if the HTML text input was just "plain", then the first
+ // Next call would set z.err to os.EOF but return a TextToken, and all
+ // subsequent Next calls would return an ErrorToken.
+ // err is never reset. Once it becomes non-nil, it stays non-nil.
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.
@@ -137,7 +149,9 @@ func (z *Tokenizer) Raw() []byte {
// 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) {
+// It sets z.err if the underlying reader returns an error.
+// Pre-condition: z.err == nil.
+func (z *Tokenizer) readByte() byte {
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
@@ -149,139 +163,168 @@ func (z *Tokenizer) readByte() (byte, os.Error) {
if 2*d > c {
buf1 = make([]byte, d, 2*c)
} else {
- buf1 = z.buf[0:d]
+ buf1 = z.buf[:d]
}
copy(buf1, z.buf[z.p0:z.p1])
- z.p0, z.p1, z.buf = 0, d, buf1[0:d]
+ z.p0, z.p1, z.buf = 0, d, buf1[: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.err = err
+ return 0
}
- z.buf = buf1[0 : d+n]
+ z.buf = buf1[:d+n]
}
x := z.buf[z.p1]
z.p1++
- return x, nil
+ return x
}
-// readTo keeps reading bytes until x is found.
-func (z *Tokenizer) readTo(x uint8) os.Error {
+// readTo keeps reading bytes until x is found or a read error occurs. If an
+// error does occur, z.err is set to that error.
+// Pre-condition: z.err == nil.
+func (z *Tokenizer) readTo(x uint8) {
for {
- c, err := z.readByte()
- if err != nil {
- return err
+ c := z.readByte()
+ if z.err != nil {
+ return
}
switch c {
case x:
- return nil
+ return
case '\\':
- _, err = z.readByte()
- if err != nil {
- return err
+ z.readByte()
+ if z.err != nil {
+ return
}
}
}
- panic("unreachable")
}
-// nextMarkupDeclaration returns the next TokenType starting with "<!".
-func (z *Tokenizer) nextMarkupDeclaration() (TokenType, os.Error) {
- // TODO: check for <!DOCTYPE ... >, don't just assume that it's a comment.
- for i := 0; i < 2; i++ {
- c, err := z.readByte()
- if err != nil {
- return TextToken, err
- }
- if c != '-' {
- return z.nextText(), nil
- }
- }
+// nextComment reads the next token starting with "<!--".
+// The opening "<!--" has already been consumed.
+// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 4 <= z.p1.
+func (z *Tokenizer) nextComment() {
// <!--> is a valid comment.
for dashCount := 2; ; {
- c, err := z.readByte()
- if err != nil {
- return TextToken, err
+ c := z.readByte()
+ if z.err != nil {
+ return
}
switch c {
case '-':
dashCount++
case '>':
if dashCount >= 2 {
- return CommentToken, nil
+ z.tt = CommentToken
+ return
}
- fallthrough
+ dashCount = 0
default:
dashCount = 0
}
}
- 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
+// nextMarkupDeclaration reads the next token starting with "<!".
+// It might be a "<!--comment-->", a "<!DOCTYPE foo>", or "<!malformed text".
+// The opening "<!" has already been consumed.
+// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 2 <= z.p1.
+func (z *Tokenizer) nextMarkupDeclaration() {
+ var c [2]byte
+ for i := 0; i < 2; i++ {
+ c[i] = z.readByte()
+ if z.err != nil {
+ return
+ }
+ }
+ if c[0] == '-' && c[1] == '-' {
+ z.nextComment()
+ return
+ }
+ z.p1 -= 2
+ const s = "DOCTYPE "
+ for i := 0; ; i++ {
+ c := z.readByte()
+ if z.err != nil {
+ return
+ }
+ // Capitalize c.
+ if 'a' <= c && c <= 'z' {
+ c = 'A' + (c - 'a')
+ }
+ if i < len(s) && c != s[i] {
+ z.nextText()
+ return
+ }
+ if c == '>' {
+ if i >= len(s) {
+ z.tt = DoctypeToken
+ }
+ return
+ }
+ }
+}
+
+// nextTag reads the next token starting with "<". It might be a "<startTag>",
+// an "</endTag>", a "<!markup declaration>", or "<malformed text".
+// The opening "<" has already been consumed.
+// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 1 <= z.p1.
+func (z *Tokenizer) nextTag() {
+ c := z.readByte()
+ if z.err != nil {
+ return
}
switch {
case c == '/':
- tt = EndTagToken
+ z.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
+ z.tt = StartTagToken
case c == '!':
- return z.nextMarkupDeclaration()
+ z.nextMarkupDeclaration()
+ return
case c == '?':
- return ErrorToken, os.NewError("html: TODO(nigeltao): implement XML processing instructions")
+ z.tt, z.err = ErrorToken, os.NewError("html: TODO: implement XML processing instructions")
+ return
default:
- return ErrorToken, os.NewError("html: TODO(nigeltao): handle malformed tags")
+ z.tt, z.err = ErrorToken, os.NewError("html: TODO: handle malformed tags")
+ return
}
for {
- c, err := z.readByte()
- if err != nil {
- return TextToken, err
+ c := z.readByte()
+ if z.err != nil {
+ return
}
switch c {
- case '"':
- err = z.readTo('"')
- if err != nil {
- return TextToken, err
- }
- case '\'':
- err = z.readTo('\'')
- if err != nil {
- return TextToken, err
+ case '"', '\'':
+ z.readTo(c)
+ if z.err != nil {
+ return
}
case '>':
- if z.buf[z.p1-2] == '/' && tt == StartTagToken {
- return SelfClosingTagToken, nil
+ if z.buf[z.p1-2] == '/' && z.tt == StartTagToken {
+ z.tt = SelfClosingTagToken
}
- return tt, nil
+ return
}
}
- panic("unreachable")
}
// nextText reads all text up until an '<'.
-func (z *Tokenizer) nextText() TokenType {
+// Pre-condition: z.tt == TextToken && z.err == nil && z.p0 + 1 <= z.p1.
+func (z *Tokenizer) nextText() {
for {
- c, err := z.readByte()
- if err != nil {
- z.tt, z.err = ErrorToken, err
- if err == os.EOF {
- z.tt = TextToken
- }
- return z.tt
+ c := z.readByte()
+ if z.err != nil {
+ return
}
if c == '<' {
z.p1--
- z.tt = TextToken
- return z.tt
+ return
}
}
- panic("unreachable")
}
// Next scans the next token and returns its type.
@@ -292,19 +335,22 @@ func (z *Tokenizer) Next() TokenType {
return z.tt
}
z.p0 = z.p1
- c, err := z.readByte()
- if err != nil {
- z.tt, z.err = ErrorToken, err
+ c := z.readByte()
+ if z.err != nil {
+ z.tt = ErrorToken
return z.tt
}
- if c == '<' {
- z.tt, z.err = z.nextTag()
+ // We assume that the next token is text unless proven otherwise.
+ z.tt = TextToken
+ if c != '<' {
+ z.nextText()
+ } else {
+ z.nextTag()
if z.tt == CommentToken && !z.ReturnComments {
continue
}
- return z.tt
}
- return z.nextText()
+ return z.tt
}
panic("unreachable")
}
@@ -331,20 +377,65 @@ func (z *Tokenizer) trim(i int) int {
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) {
+// tagName finds the tag name at the start of z.buf[i:] and returns that name
+// lower-cased, as well as the trimmed cursor location afterwards.
+func (z *Tokenizer) tagName(i int) ([]byte, int) {
+ i0 := i
+loop:
+ for ; i < z.p1; i++ {
+ c := z.buf[i]
+ switch c {
+ case ' ', '\n', '\t', '\f', '/', '>':
+ break loop
+ }
+ if 'A' <= c && c <= 'Z' {
+ z.buf[i] = c + 'a' - 'A'
+ }
+ }
+ return z.buf[i0:i], z.trim(i)
+}
+
+// unquotedAttrVal finds the unquoted attribute value at the start of z.buf[i:]
+// and returns that value, as well as the trimmed cursor location afterwards.
+func (z *Tokenizer) unquotedAttrVal(i int) ([]byte, int) {
+ i0 := i
+loop:
+ for ; i < z.p1; i++ {
+ switch z.buf[i] {
+ case ' ', '\n', '\t', '\f', '>':
+ break loop
+ case '&':
+ // TODO: unescape the entity.
+ }
+ }
+ return z.buf[i0:i], z.trim(i)
+}
+
+// attrName finds the largest attribute name at the start
+// of z.buf[i:] and returns it lower-cased, as well
+// as the trimmed cursor location after that name.
+//
+// http://dev.w3.org/html5/spec/Overview.html#syntax-attribute-name
+// TODO: unicode characters
+func (z *Tokenizer) attrName(i int) ([]byte, int) {
+ for z.buf[i] == '/' {
+ i++
+ if z.buf[i] == '>' {
+ return nil, z.trim(i)
+ }
+ }
i0 := i
loop:
for ; i < z.p1; i++ {
c := z.buf[i]
+ switch c {
+ case '>', '/', '=':
+ break loop
+ }
switch {
- case '0' <= c && c <= '9':
- // No-op.
case 'A' <= c && c <= 'Z':
z.buf[i] = c + 'a' - 'A'
- case 'a' <= c && c <= 'z':
+ case c > ' ' && c < 0x7f:
// No-op.
default:
break loop
@@ -353,25 +444,29 @@ loop:
return z.buf[i0:i], z.trim(i)
}
-// Text returns the unescaped text of a TextToken or a CommentToken.
-// The contents of the returned slice may change on the next call to Next.
+// Text returns the unescaped text of a text, comment or doctype token. The
+// contents of the returned slice may change on the next call to Next.
func (z *Tokenizer) Text() []byte {
+ var i0, i1 int
switch z.tt {
case TextToken:
- s := unescape(z.Raw())
- z.p0 = z.p1
- return s
+ i0 = z.p0
+ i1 = z.p1
case CommentToken:
- // We trim the "<!--" from the left and the "-->" from the right.
+ // Trim the "<!--" from the left and the "-->" from the right.
// "<!-->" is a valid comment, so the adjusted endpoints might overlap.
- i0 := z.p0 + 4
- i1 := z.p1 - 3
- z.p0 = z.p1
- var s []byte
- if i0 < i1 {
- s = unescape(z.buf[i0:i1])
- }
- return s
+ i0 = z.p0 + 4
+ i1 = z.p1 - 3
+ case DoctypeToken:
+ // Trim the "<!DOCTYPE " from the left and the ">" from the right.
+ i0 = z.p0 + 10
+ i1 = z.p1 - 1
+ default:
+ return nil
+ }
+ z.p0 = z.p1
+ if i0 < i1 {
+ return unescape(z.buf[i0:i1])
}
return nil
}
@@ -388,7 +483,7 @@ func (z *Tokenizer) TagName() (name []byte, hasAttr bool) {
if z.buf[i] == '/' {
i++
}
- name, z.p0 = z.lower(i)
+ name, z.p0 = z.tagName(i)
hasAttr = z.p0 != z.p1
return
}
@@ -397,27 +492,40 @@ func (z *Tokenizer) TagName() (name []byte, hasAttr bool) {
// 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, moreAttr bool) {
- key, i := z.lower(z.p0)
- // Get past the "=\"".
- if i == z.p1 || z.buf[i] != '=' {
+ key, i := z.attrName(z.p0)
+ // Check for an empty attribute value.
+ if i == z.p1 {
+ z.p0 = i
+ return
+ }
+ // Get past the equals and quote characters.
+ if z.buf[i] != '=' {
+ z.p0, moreAttr = i, true
return
}
i = z.trim(i + 1)
- if i == z.p1 || z.buf[i] != '"' {
+ if i == z.p1 {
+ z.p0 = i
+ return
+ }
+ closeQuote := z.buf[i]
+ if closeQuote != '\'' && closeQuote != '"' {
+ val, z.p0 = z.unquotedAttrVal(i)
+ moreAttr = z.p0 != z.p1
return
}
i = z.trim(i + 1)
- // Copy and unescape everything up to the closing '"'.
+ // Copy and unescape everything up to the closing quote.
dst, src := i, i
loop:
for src < z.p1 {
c := z.buf[src]
switch c {
- case '"':
+ case closeQuote:
src++
break loop
case '&':
- dst, src = unescapeEntity(z.buf, dst, src)
+ dst, src = unescapeEntity(z.buf, dst, src, true)
case '\\':
if src == z.p1 {
z.buf[dst] = '\\'
@@ -441,7 +549,7 @@ loop:
func (z *Tokenizer) Token() Token {
t := Token{Type: z.tt}
switch z.tt {
- case TextToken, CommentToken:
+ case TextToken, CommentToken, DoctypeToken:
t.Data = string(z.Text())
case StartTagToken, EndTagToken, SelfClosingTagToken:
var attr []Attribute
diff --git a/libgo/go/html/token_test.go b/libgo/go/html/token_test.go
index 5cf1f6dac30..0a0beb201b3 100644
--- a/libgo/go/html/token_test.go
+++ b/libgo/go/html/token_test.go
@@ -41,6 +41,32 @@ var tokenTests = []tokenTest{
"<a>b<c/>d</e>",
"<a>$b$<c/>$d$</e>",
},
+ // Some malformed tags that are missing a '>'.
+ {
+ "malformed tag #0",
+ `<p</p>`,
+ `<p< p="">`,
+ },
+ {
+ "malformed tag #1",
+ `<p </p>`,
+ `<p <="" p="">`,
+ },
+ {
+ "malformed tag #2",
+ `<p id=0</p>`,
+ `<p id="0&lt;/p">`,
+ },
+ {
+ "malformed tag #3",
+ `<p id="0</p>`,
+ `<p id="0&lt;/p&gt;">`,
+ },
+ {
+ "malformed tag #4",
+ `<p id="0"</p>`,
+ `<p id="0" <="" p="">`,
+ },
// Comments.
{
"comment0",
@@ -100,20 +126,77 @@ var tokenTests = []tokenTest{
"<p \t\n iD=\"a&quot;B\" foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>",
`<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
+ // A nonexistent entity. Tokenizing and converting back to a string should
// escape the "&" to become "&amp;".
{
"noSuchEntity",
`<a b="c&noSuchEntity;d">&lt;&alsoDoesntExist;&`,
`<a b="c&amp;noSuchEntity;d">$&lt;&amp;alsoDoesntExist;&amp;`,
},
+ {
+ "entity without semicolon",
+ `&notit;&notin;<a b="q=z&amp=5&notice=hello&not;=world">`,
+ `¬it;∉$<a b="q=z&amp;amp=5&amp;notice=hello¬=world">`,
+ },
+ {
+ "entity with digits",
+ "&frac12;",
+ "½",
+ },
+ // Attribute tests:
+ // http://dev.w3.org/html5/spec/Overview.html#attributes-0
+ {
+ "Empty attribute",
+ `<input disabled FOO>`,
+ `<input disabled="" foo="">`,
+ },
+ {
+ "Empty attribute, whitespace",
+ `<input disabled FOO >`,
+ `<input disabled="" foo="">`,
+ },
+ {
+ "Unquoted attribute value",
+ `<input value=yes FOO=BAR>`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Unquoted attribute value, spaces",
+ `<input value = yes FOO = BAR>`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Unquoted attribute value, trailing space",
+ `<input value=yes FOO=BAR >`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Single-quoted attribute value",
+ `<input value='yes' FOO='BAR'>`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Single-quoted attribute value, trailing space",
+ `<input value='yes' FOO='BAR' >`,
+ `<input value="yes" foo="BAR">`,
+ },
+ {
+ "Double-quoted attribute value",
+ `<input value="I'm an attribute" FOO="BAR">`,
+ `<input value="I&apos;m an attribute" foo="BAR">`,
+ },
+ {
+ "Attribute name characters",
+ `<meta http-equiv="content-type">`,
+ `<meta http-equiv="content-type">`,
+ },
}
func TestTokenizer(t *testing.T) {
loop:
for _, tt := range tokenTests {
z := NewTokenizer(bytes.NewBuffer([]byte(tt.html)))
- for i, s := range strings.Split(tt.golden, "$", -1) {
+ for i, s := range strings.Split(tt.golden, "$") {
if z.Next() == ErrorToken {
t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Error())
continue loop
diff --git a/libgo/go/http/cgi/child.go b/libgo/go/http/cgi/child.go
index e1ad7ad3221..8d0eca8d55b 100644
--- a/libgo/go/http/cgi/child.go
+++ b/libgo/go/http/cgi/child.go
@@ -18,6 +18,7 @@ import (
"os"
"strconv"
"strings"
+ "url"
)
// Request returns the HTTP request as represented in the current
@@ -45,13 +46,6 @@ func envMap(env []string) map[string]string {
return m
}
-// These environment variables are manually copied into Request
-var skipHeader = map[string]bool{
- "HTTP_HOST": true,
- "HTTP_REFERER": true,
- "HTTP_USER_AGENT": true,
-}
-
// RequestFromMap creates an http.Request from CGI variables.
// The returned Request's Body field is not populated.
func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
@@ -73,8 +67,6 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
r.Header = http.Header{}
r.Host = params["HTTP_HOST"]
- r.Referer = params["HTTP_REFERER"]
- r.UserAgent = params["HTTP_USER_AGENT"]
if lenstr := params["CONTENT_LENGTH"]; lenstr != "" {
clen, err := strconv.Atoi64(lenstr)
@@ -90,7 +82,7 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
// Copy "HTTP_FOO_BAR" variables to "Foo-Bar" Headers
for k, v := range params {
- if !strings.HasPrefix(k, "HTTP_") || skipHeader[k] {
+ if !strings.HasPrefix(k, "HTTP_") || k == "HTTP_HOST" {
continue
}
r.Header.Add(strings.Replace(k[5:], "_", "-", -1), v)
@@ -102,7 +94,7 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
// Hostname is provided, so we can reasonably construct a URL,
// even if we have to assume 'http' for the scheme.
r.RawURL = "http://" + r.Host + params["REQUEST_URI"]
- url, err := http.ParseURL(r.RawURL)
+ url, err := url.Parse(r.RawURL)
if err != nil {
return nil, os.NewError("cgi: failed to parse host and REQUEST_URI into a URL: " + r.RawURL)
}
@@ -112,7 +104,7 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
// failed to parse
if r.URL == nil {
r.RawURL = params["REQUEST_URI"]
- url, err := http.ParseURL(r.RawURL)
+ url, err := url.Parse(r.RawURL)
if err != nil {
return nil, os.NewError("cgi: failed to parse REQUEST_URI into a URL: " + r.RawURL)
}
diff --git a/libgo/go/http/cgi/child_test.go b/libgo/go/http/cgi/child_test.go
index d12947814e1..eee043bc90d 100644
--- a/libgo/go/http/cgi/child_test.go
+++ b/libgo/go/http/cgi/child_test.go
@@ -28,23 +28,19 @@ func TestRequest(t *testing.T) {
if err != nil {
t.Fatalf("RequestFromMap: %v", err)
}
- if g, e := req.UserAgent, "goclient"; e != g {
+ if g, e := req.UserAgent(), "goclient"; e != g {
t.Errorf("expected UserAgent %q; got %q", e, g)
}
if g, e := req.Method, "GET"; e != g {
t.Errorf("expected Method %q; got %q", e, g)
}
- if g, e := req.Header.Get("User-Agent"), ""; e != g {
- // Tests that we don't put recognized headers in the map
- t.Errorf("expected User-Agent %q; got %q", e, g)
- }
if g, e := req.Header.Get("Content-Type"), "text/xml"; e != g {
t.Errorf("expected Content-Type %q; got %q", e, g)
}
if g, e := req.ContentLength, int64(123); e != g {
t.Errorf("expected ContentLength %d; got %d", e, g)
}
- if g, e := req.Referer, "elsewhere"; e != g {
+ if g, e := req.Referer(), "elsewhere"; e != g {
t.Errorf("expected Referer %q; got %q", e, g)
}
if req.Header == nil {
diff --git a/libgo/go/http/cgi/host.go b/libgo/go/http/cgi/host.go
index 7e4ccf881d9..f7de89f9974 100644
--- a/libgo/go/http/cgi/host.go
+++ b/libgo/go/http/cgi/host.go
@@ -16,7 +16,6 @@ package cgi
import (
"bufio"
- "bytes"
"exec"
"fmt"
"http"
@@ -47,6 +46,12 @@ type Handler struct {
Path string // path to the CGI executable
Root string // root URI prefix of handler or empty for "/"
+ // Dir specifies the CGI executable's working directory.
+ // If Dir is empty, the base directory of Path is used.
+ // If Path has no base directory, the current working
+ // directory is used.
+ Dir string
+
Env []string // extra environment variables to set, if any, as "key=value"
InheritEnv []string // environment variables to inherit from host, as "key"
Logger *log.Logger // optional log for errors or nil to use log.Print
@@ -106,20 +111,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
env = append(env, "HTTPS=on")
}
- if len(req.Cookie) > 0 {
- b := new(bytes.Buffer)
- for idx, c := range req.Cookie {
- if idx > 0 {
- b.Write([]byte("; "))
- }
- fmt.Fprintf(b, "%s=%s", c.Name, c.Value)
- }
- env = append(env, "HTTP_COOKIE="+b.String())
- }
-
for k, v := range req.Header {
k = strings.Map(upperCaseAndUnderscore, k)
- env = append(env, "HTTP_"+k+"="+strings.Join(v, ", "))
+ joinStr := ", "
+ if k == "COOKIE" {
+ joinStr = "; "
+ }
+ env = append(env, "HTTP_"+k+"="+strings.Join(v, joinStr))
}
if req.ContentLength > 0 {
@@ -133,11 +131,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
env = append(env, h.Env...)
}
- path := os.Getenv("PATH")
- if path == "" {
- path = "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
+ envPath := os.Getenv("PATH")
+ if envPath == "" {
+ envPath = "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin"
}
- env = append(env, "PATH="+path)
+ env = append(env, "PATH="+envPath)
for _, e := range h.InheritEnv {
if v := os.Getenv(e); v != "" {
@@ -151,39 +149,47 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}
}
- cwd, pathBase := filepath.Split(h.Path)
+ var cwd, path string
+ if h.Dir != "" {
+ path = h.Path
+ cwd = h.Dir
+ } else {
+ cwd, path = filepath.Split(h.Path)
+ }
if cwd == "" {
cwd = "."
}
- args := []string{h.Path}
- args = append(args, h.Args...)
-
- cmd, err := exec.Run(
- pathBase,
- args,
- env,
- cwd,
- exec.Pipe, // stdin
- exec.Pipe, // stdout
- exec.PassThrough, // stderr (for now)
- )
- if err != nil {
+ internalError := func(err os.Error) {
rw.WriteHeader(http.StatusInternalServerError)
h.printf("CGI error: %v", err)
- return
}
- defer func() {
- cmd.Stdin.Close()
- cmd.Stdout.Close()
- cmd.Wait(0) // no zombies
- }()
+ cmd := &exec.Cmd{
+ Path: path,
+ Args: append([]string{h.Path}, h.Args...),
+ Dir: cwd,
+ Env: env,
+ Stderr: os.Stderr, // for now
+ }
if req.ContentLength != 0 {
- go io.Copy(cmd.Stdin, req.Body)
+ cmd.Stdin = req.Body
+ }
+ stdoutRead, err := cmd.StdoutPipe()
+ if err != nil {
+ internalError(err)
+ return
+ }
+
+ err = cmd.Start()
+ if err != nil {
+ internalError(err)
+ return
}
+ defer cmd.Wait()
+ defer stdoutRead.Close()
- linebody, _ := bufio.NewReaderSize(cmd.Stdout, 1024)
+ linebody, _ := bufio.NewReaderSize(stdoutRead, 1024)
headers := make(http.Header)
statusCode := 0
for {
@@ -204,7 +210,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if len(line) == 0 {
break
}
- parts := strings.Split(string(line), ":", 2)
+ parts := strings.SplitN(string(line), ":", 2)
if len(parts) < 2 {
h.printf("cgi: bogus header line: %s", string(line))
continue
@@ -270,7 +276,7 @@ func (h *Handler) printf(format string, v ...interface{}) {
}
func (h *Handler) handleInternalRedirect(rw http.ResponseWriter, req *http.Request, path string) {
- url, err := req.URL.ParseURL(path)
+ url, err := req.URL.Parse(path)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
h.printf("cgi: error resolving local URI path %q: %v", path, err)
diff --git a/libgo/go/http/cgi/host_test.go b/libgo/go/http/cgi/host_test.go
index 9ac085f2f3a..1dc3abdbb32 100644
--- a/libgo/go/http/cgi/host_test.go
+++ b/libgo/go/http/cgi/host_test.go
@@ -12,25 +12,17 @@ import (
"fmt"
"http"
"http/httptest"
+ "io"
"os"
+ "net"
+ "path/filepath"
+ "strconv"
"strings"
"testing"
+ "time"
+ "runtime"
)
-var cgiScriptWorks = canRun("./testdata/test.cgi")
-
-func canRun(s string) bool {
- c, err := exec.Run(s, []string{s}, nil, ".", exec.DevNull, exec.DevNull, exec.DevNull)
- if err != nil {
- return false
- }
- w, err := c.Wait(0)
- if err != nil {
- return false
- }
- return w.Exited() && w.ExitStatus() == 0
-}
-
func newRequest(httpreq string) *http.Request {
buf := bufio.NewReader(strings.NewReader(httpreq))
req, err := http.ReadRequest(buf)
@@ -60,7 +52,7 @@ readlines:
}
linesRead++
trimmedLine := strings.TrimRight(line, "\r\n")
- split := strings.Split(trimmedLine, "=", 2)
+ split := strings.SplitN(trimmedLine, "=", 2)
if len(split) != 2 {
t.Fatalf("Unexpected %d parts from invalid line number %v: %q; existing map=%v",
len(split), linesRead, line, m)
@@ -76,8 +68,15 @@ readlines:
return rw
}
+var cgiTested = false
+var cgiWorks bool
+
func skipTest(t *testing.T) bool {
- if !cgiScriptWorks {
+ if !cgiTested {
+ cgiTested = true
+ cgiWorks = exec.Command("./testdata/test.cgi").Run() == nil
+ }
+ if !cgiWorks {
// No Perl on Windows, needed by test.cgi
// TODO: make the child process be Go, not Perl.
t.Logf("Skipping test: test.cgi failed.")
@@ -86,7 +85,6 @@ func skipTest(t *testing.T) bool {
return false
}
-
func TestCGIBasicGet(t *testing.T) {
if skipTest(t) {
return
@@ -308,3 +306,144 @@ func TestInternalRedirect(t *testing.T) {
}
runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap)
}
+
+// TestCopyError tests that we kill the process if there's an error copying
+// its output. (for example, from the client having gone away)
+func TestCopyError(t *testing.T) {
+ if skipTest(t) || runtime.GOOS == "windows" {
+ return
+ }
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ ts := httptest.NewServer(h)
+ defer ts.Close()
+
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ req, _ := http.NewRequest("GET", "http://example.com/test.cgi?bigresponse=1", nil)
+ err = req.Write(conn)
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+
+ res, err := http.ReadResponse(bufio.NewReader(conn), req)
+ if err != nil {
+ t.Fatalf("ReadResponse: %v", err)
+ }
+
+ pidstr := res.Header.Get("X-CGI-Pid")
+ if pidstr == "" {
+ t.Fatalf("expected an X-CGI-Pid header in response")
+ }
+ pid, err := strconv.Atoi(pidstr)
+ if err != nil {
+ t.Fatalf("invalid X-CGI-Pid value")
+ }
+
+ var buf [5000]byte
+ n, err := io.ReadFull(res.Body, buf[:])
+ if err != nil {
+ t.Fatalf("ReadFull: %d bytes, %v", n, err)
+ }
+
+ childRunning := func() bool {
+ p, err := os.FindProcess(pid)
+ if err != nil {
+ return false
+ }
+ return p.Signal(os.UnixSignal(0)) == nil
+ }
+
+ if !childRunning() {
+ t.Fatalf("pre-conn.Close, expected child to be running")
+ }
+ conn.Close()
+
+ if tries := 0; childRunning() {
+ for tries < 15 && childRunning() {
+ time.Sleep(50e6 * int64(tries))
+ tries++
+ }
+ if childRunning() {
+ t.Fatalf("post-conn.Close, expected child to be gone")
+ }
+ }
+}
+
+func TestDirUnix(t *testing.T) {
+ if skipTest(t) || runtime.GOOS == "windows" {
+ return
+ }
+
+ cwd, _ := os.Getwd()
+ h := &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ Dir: cwd,
+ }
+ expectedMap := map[string]string{
+ "cwd": cwd,
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+
+ cwd, _ = os.Getwd()
+ cwd = filepath.Join(cwd, "testdata")
+ h = &Handler{
+ Path: "testdata/test.cgi",
+ Root: "/test.cgi",
+ }
+ expectedMap = map[string]string{
+ "cwd": cwd,
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
+
+func TestDirWindows(t *testing.T) {
+ if skipTest(t) || runtime.GOOS != "windows" {
+ return
+ }
+
+ cgifile, _ := filepath.Abs("testdata/test.cgi")
+
+ var perl string
+ var err os.Error
+ perl, err = exec.LookPath("perl")
+ if err != nil {
+ return
+ }
+ perl, _ = filepath.Abs(perl)
+
+ cwd, _ := os.Getwd()
+ h := &Handler{
+ Path: perl,
+ Root: "/test.cgi",
+ Dir: cwd,
+ Args: []string{cgifile},
+ Env: []string{"SCRIPT_FILENAME=" + cgifile},
+ }
+ expectedMap := map[string]string{
+ "cwd": cwd,
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+
+ // If not specify Dir on windows, working directory should be
+ // base directory of perl.
+ cwd, _ = filepath.Split(perl)
+ if cwd != "" && cwd[len(cwd)-1] == filepath.Separator {
+ cwd = cwd[:len(cwd)-1]
+ }
+ h = &Handler{
+ Path: perl,
+ Root: "/test.cgi",
+ Args: []string{cgifile},
+ Env: []string{"SCRIPT_FILENAME=" + cgifile},
+ }
+ expectedMap = map[string]string{
+ "cwd": cwd,
+ }
+ runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
+}
diff --git a/libgo/go/http/chunked.go b/libgo/go/http/chunked.go
index 66195f06b96..6c23e691f02 100644
--- a/libgo/go/http/chunked.go
+++ b/libgo/go/http/chunked.go
@@ -6,19 +6,30 @@ package http
import (
"io"
+ "log"
"os"
"strconv"
+ "bufio"
)
// NewChunkedWriter returns a new writer that translates writes into HTTP
-// "chunked" format before writing them to w. Closing the returned writer
+// "chunked" format before writing them to w. Closing the returned writer
// sends the final 0-length chunk that marks the end of the stream.
+//
+// NewChunkedWriter is not needed by normal applications. The http
+// package adds chunking automatically if handlers don't set a
+// Content-Length header. Using NewChunkedWriter inside a handler
+// would result in double chunking or chunking with a Content-Length
+// length, both of which are wrong.
func NewChunkedWriter(w io.Writer) io.WriteCloser {
+ if _, bad := w.(*response); bad {
+ log.Printf("warning: using NewChunkedWriter in an http.Handler; expect corrupt output")
+ }
return &chunkedWriter{w}
}
// Writing to ChunkedWriter translates to writing in HTTP chunked Transfer
-// Encoding wire format to the undering Wire writer.
+// Encoding wire format to the underlying Wire writer.
type chunkedWriter struct {
Wire io.Writer
}
@@ -54,3 +65,13 @@ func (cw *chunkedWriter) Close() os.Error {
_, err := io.WriteString(cw.Wire, "0\r\n")
return err
}
+
+// NewChunkedReader returns a new reader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The reader returns os.EOF when the final 0-length chunk is read.
+//
+// NewChunkedReader is not needed by normal applications. The http package
+// automatically decodes chunking when reading response bodies.
+func NewChunkedReader(r *bufio.Reader) io.Reader {
+ return &chunkedReader{r: r}
+}
diff --git a/libgo/go/http/client.go b/libgo/go/http/client.go
index d73cbc8550c..44b3443fc40 100644
--- a/libgo/go/http/client.go
+++ b/libgo/go/http/client.go
@@ -7,18 +7,21 @@
package http
import (
- "bytes"
"encoding/base64"
"fmt"
"io"
- "io/ioutil"
"os"
- "strconv"
"strings"
+ "url"
)
// A Client is an HTTP client. Its zero value (DefaultClient) is a usable client
// that uses DefaultTransport.
+//
+// The Client's Transport typically has internal state (cached
+// TCP connections), so Clients should be reused instead of created as
+// needed. Clients are safe for concurrent use by multiple goroutines.
+//
// Client is not yet very configurable.
type Client struct {
Transport RoundTripper // if nil, DefaultTransport is used
@@ -39,6 +42,9 @@ var DefaultClient = &Client{}
// RoundTripper is an interface representing the ability to execute a
// single HTTP transaction, obtaining the Response for a given Request.
+//
+// A RoundTripper must be safe for concurrent use by multiple
+// goroutines.
type RoundTripper interface {
// RoundTrip executes a single HTTP transaction, returning
// the Response for the request req. RoundTrip should not
@@ -74,10 +80,12 @@ type readClose struct {
//
// Generally Get, Post, or PostForm will be used instead of Do.
func (c *Client) Do(req *Request) (resp *Response, err os.Error) {
+ if req.Method == "GET" || req.Method == "HEAD" {
+ return c.doFollowingRedirects(req)
+ }
return send(req, c.Transport)
}
-
// send issues an HTTP request. Caller should close resp.Body when done reading from it.
func send(req *Request, t RoundTripper) (resp *Response, err os.Error) {
if t == nil {
@@ -97,13 +105,10 @@ func send(req *Request, t RoundTripper) (resp *Response, err os.Error) {
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(Header)
}
- req.Header.Set("Authorization", "Basic "+string(encoded))
+ req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(info)))
}
return t.RoundTrip(req)
}
@@ -126,13 +131,10 @@ func shouldRedirect(statusCode int) bool {
// 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 from it.
//
// Get is a convenience wrapper around DefaultClient.Get.
-func Get(url string) (r *Response, finalURL string, err os.Error) {
+func Get(url string) (r *Response, err os.Error) {
return DefaultClient.Get(url)
}
@@ -145,70 +147,75 @@ func Get(url string) (r *Response, finalURL string, err os.Error) {
// 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 from it.
-func (c *Client) Get(url string) (r *Response, finalURL string, err os.Error) {
+func (c *Client) Get(url string) (r *Response, err os.Error) {
+ req, err := NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ return c.doFollowingRedirects(req)
+}
+
+func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error) {
// TODO: if/when we add cookie support, the redirected request shouldn't
// necessarily supply the same cookies as the original.
- var base *URL
+ var base *url.URL
redirectChecker := c.CheckRedirect
if redirectChecker == nil {
redirectChecker = defaultCheckRedirect
}
var via []*Request
+ req := ireq
+ urlStr := "" // next relative or absolute URL to fetch (after first request)
for redirect := 0; ; redirect++ {
- var req Request
- req.Method = "GET"
- req.Header = make(Header)
- if base == nil {
- req.URL, err = ParseURL(url)
- } else {
- req.URL, err = base.ParseURL(url)
- }
- if err != nil {
- break
- }
- if len(via) > 0 {
- // Add the Referer header.
- lastReq := via[len(via)-1]
- if lastReq.URL.Scheme != "https" {
- req.Referer = lastReq.URL.String()
- }
-
- err = redirectChecker(&req, via)
+ if redirect != 0 {
+ req = new(Request)
+ req.Method = ireq.Method
+ req.Header = make(Header)
+ req.URL, err = base.Parse(urlStr)
if err != nil {
break
}
+ if len(via) > 0 {
+ // Add the Referer header.
+ lastReq := via[len(via)-1]
+ if lastReq.URL.Scheme != "https" {
+ req.Header.Set("Referer", lastReq.URL.String())
+ }
+
+ err = redirectChecker(req, via)
+ if err != nil {
+ break
+ }
+ }
}
- url = req.URL.String()
- if r, err = send(&req, c.Transport); err != nil {
+ urlStr = req.URL.String()
+ if r, err = send(req, c.Transport); err != nil {
break
}
if shouldRedirect(r.StatusCode) {
r.Body.Close()
- if url = r.Header.Get("Location"); url == "" {
- err = os.ErrorString(fmt.Sprintf("%d response missing Location header", r.StatusCode))
+ if urlStr = r.Header.Get("Location"); urlStr == "" {
+ err = os.NewError(fmt.Sprintf("%d response missing Location header", r.StatusCode))
break
}
base = req.URL
- via = append(via, &req)
+ via = append(via, req)
continue
}
- finalURL = url
return
}
- err = &URLError{"Get", url, err}
+ method := ireq.Method
+ err = &url.Error{method[0:1] + strings.ToLower(method[1:]), urlStr, err}
return
}
func defaultCheckRedirect(req *Request, via []*Request) os.Error {
if len(via) >= 10 {
- return os.ErrorString("stopped after 10 redirects")
+ return os.NewError("stopped after 10 redirects")
}
return nil
}
@@ -226,23 +233,12 @@ func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Erro
//
// Caller should close r.Body when done reading from it.
func (c *Client) 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 = ioutil.NopCloser(body)
- req.Header = Header{
- "Content-Type": {bodyType},
- }
- req.TransferEncoding = []string{"chunked"}
-
- req.URL, err = ParseURL(url)
+ req, err := NewRequest("POST", url, body)
if err != nil {
return nil, err
}
-
- return send(&req, c.Transport)
+ req.Header.Set("Content-Type", bodyType)
+ return send(req, c.Transport)
}
// PostForm issues a POST to the specified URL,
@@ -251,7 +247,7 @@ func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response,
// Caller should close r.Body when done reading from it.
//
// PostForm is a wrapper around DefaultClient.PostForm
-func PostForm(url string, data map[string]string) (r *Response, err os.Error) {
+func PostForm(url string, data url.Values) (r *Response, err os.Error) {
return DefaultClient.PostForm(url, data)
}
@@ -259,50 +255,36 @@ func PostForm(url string, data map[string]string) (r *Response, err os.Error) {
// with data's keys and values urlencoded as the request body.
//
// Caller should close r.Body when done reading from it.
-func (c *Client) 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 = ioutil.NopCloser(body)
- req.Header = Header{
- "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, c.Transport)
+func (c *Client) PostForm(url string, data url.Values) (r *Response, err os.Error) {
+ return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
-// 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.
+// Head issues a HEAD to the specified URL. If the response is one of the
+// following redirect codes, Head follows the redirect after calling the
+// Client's CheckRedirect function.
+//
+// 301 (Moved Permanently)
+// 302 (Found)
+// 303 (See Other)
+// 307 (Temporary Redirect)
//
// Head is a wrapper around DefaultClient.Head
func Head(url string) (r *Response, err os.Error) {
return DefaultClient.Head(url)
}
-// Head issues a HEAD to the specified URL.
+// Head issues a HEAD to the specified URL. If the response is one of the
+// following redirect codes, Head follows the redirect after calling the
+// Client's CheckRedirect function.
+//
+// 301 (Moved Permanently)
+// 302 (Found)
+// 303 (See Other)
+// 307 (Temporary Redirect)
func (c *Client) Head(url string) (r *Response, err os.Error) {
- var req Request
- req.Method = "HEAD"
- if req.URL, err = ParseURL(url); err != nil {
- return
+ req, err := NewRequest("HEAD", url, nil)
+ if err != nil {
+ return nil, err
}
- return send(&req, c.Transport)
+ return c.doFollowingRedirects(req)
}
diff --git a/libgo/go/http/client_test.go b/libgo/go/http/client_test.go
index 59d62c1c9d4..8efb1d989df 100644
--- a/libgo/go/http/client_test.go
+++ b/libgo/go/http/client_test.go
@@ -10,11 +10,14 @@ import (
"fmt"
. "http"
"http/httptest"
+ "io"
"io/ioutil"
+ "net"
"os"
"strconv"
"strings"
"testing"
+ "url"
)
var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -26,7 +29,7 @@ func TestClient(t *testing.T) {
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
- r, _, err := Get(ts.URL)
+ r, err := Get(ts.URL)
var b []byte
if err == nil {
b, err = ioutil.ReadAll(r.Body)
@@ -77,13 +80,78 @@ func TestGetRequestFormat(t *testing.T) {
}
}
+func TestPostRequestFormat(t *testing.T) {
+ tr := &recordingTransport{}
+ client := &Client{Transport: tr}
+
+ url := "http://dummy.faketld/"
+ json := `{"key":"value"}`
+ b := strings.NewReader(json)
+ client.Post(url, "application/json", b) // Note: doesn't hit network
+
+ if tr.req.Method != "POST" {
+ t.Errorf("got method %q, want %q", tr.req.Method, "POST")
+ }
+ if tr.req.URL.String() != url {
+ t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
+ }
+ if tr.req.Header == nil {
+ t.Fatalf("expected non-nil request Header")
+ }
+ if tr.req.Close {
+ t.Error("got Close true, want false")
+ }
+ if g, e := tr.req.ContentLength, int64(len(json)); g != e {
+ t.Errorf("got ContentLength %d, want %d", g, e)
+ }
+}
+
+func TestPostFormRequestFormat(t *testing.T) {
+ tr := &recordingTransport{}
+ client := &Client{Transport: tr}
+
+ urlStr := "http://dummy.faketld/"
+ form := make(url.Values)
+ form.Set("foo", "bar")
+ form.Add("foo", "bar2")
+ form.Set("bar", "baz")
+ client.PostForm(urlStr, form) // Note: doesn't hit network
+
+ if tr.req.Method != "POST" {
+ t.Errorf("got method %q, want %q", tr.req.Method, "POST")
+ }
+ if tr.req.URL.String() != urlStr {
+ t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlStr)
+ }
+ if tr.req.Header == nil {
+ t.Fatalf("expected non-nil request Header")
+ }
+ if g, e := tr.req.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; g != e {
+ t.Errorf("got Content-Type %q, want %q", g, e)
+ }
+ if tr.req.Close {
+ t.Error("got Close true, want false")
+ }
+ expectedBody := "bar=baz&foo=bar&foo=bar2"
+ if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e {
+ t.Errorf("got ContentLength %d, want %d", g, e)
+ }
+ bodyb, err := ioutil.ReadAll(tr.req.Body)
+ if err != nil {
+ t.Fatalf("ReadAll on req.Body: %v", err)
+ }
+ if g := string(bodyb); g != expectedBody {
+ t.Errorf("got body %q, want %q", g, expectedBody)
+ }
+}
+
func TestRedirects(t *testing.T) {
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
n, _ := strconv.Atoi(r.FormValue("n"))
// Test Referer header. (7 is arbitrary position to test at)
if n == 7 {
- if g, e := r.Referer, ts.URL+"/?n=6"; e != g {
+ if g, e := r.Referer(), ts.URL+"/?n=6"; e != g {
t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
}
}
@@ -96,9 +164,22 @@ func TestRedirects(t *testing.T) {
defer ts.Close()
c := &Client{}
- _, _, err := c.Get(ts.URL)
+ _, err := c.Get(ts.URL)
if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
- t.Errorf("with default client, expected error %q, got %q", e, g)
+ t.Errorf("with default client Get, expected error %q, got %q", e, g)
+ }
+
+ // HEAD request should also have the ability to follow redirects.
+ _, err = c.Head(ts.URL)
+ if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
+ t.Errorf("with default client Head, expected error %q, got %q", e, g)
+ }
+
+ // Do should also follow redirects.
+ greq, _ := NewRequest("GET", ts.URL, nil)
+ _, err = c.Do(greq)
+ if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
+ t.Errorf("with default client Do, expected error %q, got %q", e, g)
}
var checkErr os.Error
@@ -107,7 +188,8 @@ func TestRedirects(t *testing.T) {
lastVia = via
return checkErr
}}
- _, finalUrl, err := c.Get(ts.URL)
+ res, err := c.Get(ts.URL)
+ finalUrl := res.Request.URL.String()
if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
t.Errorf("with custom client, expected error %q, got %q", e, g)
}
@@ -119,8 +201,92 @@ func TestRedirects(t *testing.T) {
}
checkErr = os.NewError("no redirects allowed")
- _, finalUrl, err = c.Get(ts.URL)
+ res, err = c.Get(ts.URL)
+ finalUrl = res.Request.URL.String()
if e, g := "Get /?n=1: no redirects allowed", fmt.Sprintf("%v", err); e != g {
t.Errorf("with redirects forbidden, expected error %q, got %q", e, g)
}
}
+
+func TestStreamingGet(t *testing.T) {
+ say := make(chan string)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.(Flusher).Flush()
+ for str := range say {
+ w.Write([]byte(str))
+ w.(Flusher).Flush()
+ }
+ }))
+ defer ts.Close()
+
+ c := &Client{}
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var buf [10]byte
+ for _, str := range []string{"i", "am", "also", "known", "as", "comet"} {
+ say <- str
+ n, err := io.ReadFull(res.Body, buf[0:len(str)])
+ if err != nil {
+ t.Fatalf("ReadFull on %q: %v", str, err)
+ }
+ if n != len(str) {
+ t.Fatalf("Receiving %q, only read %d bytes", str, n)
+ }
+ got := string(buf[0:n])
+ if got != str {
+ t.Fatalf("Expected %q, got %q", str, got)
+ }
+ }
+ close(say)
+ _, err = io.ReadFull(res.Body, buf[0:1])
+ if err != os.EOF {
+ t.Fatalf("at end expected EOF, got %v", err)
+ }
+}
+
+type writeCountingConn struct {
+ net.Conn
+ count *int
+}
+
+func (c *writeCountingConn) Write(p []byte) (int, os.Error) {
+ *c.count++
+ return c.Conn.Write(p)
+}
+
+// TestClientWrites verifies that client requests are buffered and we
+// don't send a TCP packet per line of the http request + body.
+func TestClientWrites(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ }))
+ defer ts.Close()
+
+ writes := 0
+ dialer := func(netz string, addr string) (net.Conn, os.Error) {
+ c, err := net.Dial(netz, addr)
+ if err == nil {
+ c = &writeCountingConn{c, &writes}
+ }
+ return c, err
+ }
+ c := &Client{Transport: &Transport{Dial: dialer}}
+
+ _, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if writes != 1 {
+ t.Errorf("Get request did %d Write calls, want 1", writes)
+ }
+
+ writes = 0
+ _, err = c.PostForm(ts.URL, url.Values{"foo": {"bar"}})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if writes != 1 {
+ t.Errorf("Post request did %d Write calls, want 1", writes)
+ }
+}
diff --git a/libgo/go/http/cookie.go b/libgo/go/http/cookie.go
index cc51316438a..fe70431bbbc 100644
--- a/libgo/go/http/cookie.go
+++ b/libgo/go/http/cookie.go
@@ -7,9 +7,6 @@ package http
import (
"bytes"
"fmt"
- "io"
- "os"
- "sort"
"strconv"
"strings"
"time"
@@ -40,30 +37,25 @@ type Cookie struct {
}
// readSetCookies parses all "Set-Cookie" values from
-// the header h, removes the successfully parsed values from the
-// "Set-Cookie" key in h and returns the parsed Cookies.
+// the header h and returns the successfully parsed Cookies.
func readSetCookies(h Header) []*Cookie {
cookies := []*Cookie{}
- var unparsedLines []string
for _, line := range h["Set-Cookie"] {
- parts := strings.Split(strings.TrimSpace(line), ";", -1)
+ parts := strings.Split(strings.TrimSpace(line), ";")
if len(parts) == 1 && parts[0] == "" {
continue
}
parts[0] = strings.TrimSpace(parts[0])
j := strings.Index(parts[0], "=")
if j < 0 {
- unparsedLines = append(unparsedLines, line)
continue
}
name, value := parts[0][:j], parts[0][j+1:]
if !isCookieNameValid(name) {
- unparsedLines = append(unparsedLines, line)
continue
}
value, success := parseCookieValue(value)
if !success {
- unparsedLines = append(unparsedLines, line)
continue
}
c := &Cookie{
@@ -81,12 +73,17 @@ func readSetCookies(h Header) []*Cookie {
if j := strings.Index(attr, "="); j >= 0 {
attr, val = attr[:j], attr[j+1:]
}
- val, success = parseCookieValue(val)
+ lowerAttr := strings.ToLower(attr)
+ parseCookieValueFn := parseCookieValue
+ if lowerAttr == "expires" {
+ parseCookieValueFn = parseCookieExpiresValue
+ }
+ val, success = parseCookieValueFn(val)
if !success {
c.Unparsed = append(c.Unparsed, parts[i])
continue
}
- switch strings.ToLower(attr) {
+ switch lowerAttr {
case "secure":
c.Secure = true
continue
@@ -112,8 +109,11 @@ func readSetCookies(h Header) []*Cookie {
c.RawExpires = val
exptime, err := time.Parse(time.RFC1123, val)
if err != nil {
- c.Expires = time.Time{}
- break
+ exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val)
+ if err != nil {
+ c.Expires = time.Time{}
+ break
+ }
}
c.Expires = *exptime
continue
@@ -126,66 +126,56 @@ func readSetCookies(h Header) []*Cookie {
}
cookies = append(cookies, c)
}
- h["Set-Cookie"] = unparsedLines, unparsedLines != nil
return cookies
}
-// writeSetCookies writes the wire representation of the set-cookies
-// to w. Each cookie is written on a separate "Set-Cookie: " line.
-// This choice is made because HTTP parsers tend to have a limit on
-// line-length, so it seems safer to place cookies on separate lines.
-func writeSetCookies(w io.Writer, kk []*Cookie) os.Error {
- if kk == nil {
- return nil
- }
- lines := make([]string, 0, len(kk))
+// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
+func SetCookie(w ResponseWriter, cookie *Cookie) {
+ w.Header().Add("Set-Cookie", cookie.String())
+}
+
+// String returns the serialization of the cookie for use in a Cookie
+// header (if only Name and Value are set) or a Set-Cookie response
+// header (if other fields are set).
+func (c *Cookie) String() string {
var b bytes.Buffer
- for _, c := range kk {
- b.Reset()
- fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
- if len(c.Path) > 0 {
- fmt.Fprintf(&b, "; Path=%s", sanitizeValue(c.Path))
- }
- if len(c.Domain) > 0 {
- fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
- }
- if len(c.Expires.Zone) > 0 {
- fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
- }
- if c.MaxAge > 0 {
- fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
- } else if c.MaxAge < 0 {
- fmt.Fprintf(&b, "; Max-Age=0")
- }
- if c.HttpOnly {
- fmt.Fprintf(&b, "; HttpOnly")
- }
- if c.Secure {
- fmt.Fprintf(&b, "; Secure")
- }
- lines = append(lines, "Set-Cookie: "+b.String()+"\r\n")
+ fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
+ if len(c.Path) > 0 {
+ fmt.Fprintf(&b, "; Path=%s", sanitizeValue(c.Path))
}
- sort.SortStrings(lines)
- for _, l := range lines {
- if _, err := io.WriteString(w, l); err != nil {
- return err
- }
+ if len(c.Domain) > 0 {
+ fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
+ }
+ if len(c.Expires.Zone) > 0 {
+ fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
+ }
+ if c.MaxAge > 0 {
+ fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
+ } else if c.MaxAge < 0 {
+ fmt.Fprintf(&b, "; Max-Age=0")
}
- return nil
+ if c.HttpOnly {
+ fmt.Fprintf(&b, "; HttpOnly")
+ }
+ if c.Secure {
+ fmt.Fprintf(&b, "; Secure")
+ }
+ return b.String()
}
-// readCookies parses all "Cookie" values from
-// the header h, removes the successfully parsed values from the
-// "Cookie" key in h and returns the parsed Cookies.
-func readCookies(h Header) []*Cookie {
+// readCookies parses all "Cookie" values from the header h and
+// returns the successfully parsed Cookies.
+//
+// if filter isn't empty, only cookies of that name are returned
+func readCookies(h Header, filter string) []*Cookie {
cookies := []*Cookie{}
lines, ok := h["Cookie"]
if !ok {
return cookies
}
- unparsedLines := []string{}
+
for _, line := range lines {
- parts := strings.Split(strings.TrimSpace(line), ";", -1)
+ parts := strings.Split(strings.TrimSpace(line), ";")
if len(parts) == 1 && parts[0] == "" {
continue
}
@@ -196,46 +186,27 @@ func readCookies(h Header) []*Cookie {
if len(parts[i]) == 0 {
continue
}
- attr, val := parts[i], ""
- if j := strings.Index(attr, "="); j >= 0 {
- attr, val = attr[:j], attr[j+1:]
+ name, val := parts[i], ""
+ if j := strings.Index(name, "="); j >= 0 {
+ name, val = name[:j], name[j+1:]
+ }
+ if !isCookieNameValid(name) {
+ continue
}
- if !isCookieNameValid(attr) {
+ if filter != "" && filter != name {
continue
}
val, success := parseCookieValue(val)
if !success {
continue
}
- cookies = append(cookies, &Cookie{Name: attr, Value: val})
+ cookies = append(cookies, &Cookie{Name: name, Value: val})
parsedPairs++
}
- if parsedPairs == 0 {
- unparsedLines = append(unparsedLines, line)
- }
}
- h["Cookie"] = unparsedLines, len(unparsedLines) > 0
return cookies
}
-// writeCookies writes the wire representation of the cookies
-// to w. Each cookie is written on a separate "Cookie: " line.
-// This choice is made because HTTP parsers tend to have a limit on
-// line-length, so it seems safer to place cookies on separate lines.
-func writeCookies(w io.Writer, kk []*Cookie) os.Error {
- lines := make([]string, 0, len(kk))
- for _, c := range kk {
- lines = append(lines, fmt.Sprintf("Cookie: %s=%s\r\n", sanitizeName(c.Name), sanitizeValue(c.Value)))
- }
- sort.SortStrings(lines)
- for _, l := range lines {
- if _, err := io.WriteString(w, l); err != nil {
- return err
- }
- }
- return nil
-}
-
func sanitizeName(n string) string {
n = strings.Replace(n, "\n", "-", -1)
n = strings.Replace(n, "\r", "-", -1)
@@ -257,7 +228,7 @@ func unquoteCookieValue(v string) string {
}
func isCookieByte(c byte) bool {
- switch true {
+ switch {
case c == 0x21, 0x23 <= c && c <= 0x2b, 0x2d <= c && c <= 0x3a,
0x3c <= c && c <= 0x5b, 0x5d <= c && c <= 0x7e:
return true
@@ -265,10 +236,22 @@ func isCookieByte(c byte) bool {
return false
}
+func isCookieExpiresByte(c byte) (ok bool) {
+ return isCookieByte(c) || c == ',' || c == ' '
+}
+
func parseCookieValue(raw string) (string, bool) {
+ return parseCookieValueUsing(raw, isCookieByte)
+}
+
+func parseCookieExpiresValue(raw string) (string, bool) {
+ return parseCookieValueUsing(raw, isCookieExpiresByte)
+}
+
+func parseCookieValueUsing(raw string, validByte func(byte) bool) (string, bool) {
raw = unquoteCookieValue(raw)
for i := 0; i < len(raw); i++ {
- if !isCookieByte(raw[i]) {
+ if !validByte(raw[i]) {
return "", false
}
}
diff --git a/libgo/go/http/cookie_test.go b/libgo/go/http/cookie_test.go
index a3ae85cd6c9..d7aeda0be17 100644
--- a/libgo/go/http/cookie_test.go
+++ b/libgo/go/http/cookie_test.go
@@ -5,61 +5,104 @@
package http
import (
- "bytes"
"fmt"
"json"
+ "os"
"reflect"
"testing"
+ "time"
)
-
var writeSetCookiesTests = []struct {
- Cookies []*Cookie
- Raw string
+ Cookie *Cookie
+ Raw string
}{
{
- []*Cookie{
- &Cookie{Name: "cookie-1", Value: "v$1"},
- &Cookie{Name: "cookie-2", Value: "two", MaxAge: 3600},
- &Cookie{Name: "cookie-3", Value: "three", Domain: ".example.com"},
- &Cookie{Name: "cookie-4", Value: "four", Path: "/restricted/"},
- },
- "Set-Cookie: cookie-1=v$1\r\n" +
- "Set-Cookie: cookie-2=two; Max-Age=3600\r\n" +
- "Set-Cookie: cookie-3=three; Domain=.example.com\r\n" +
- "Set-Cookie: cookie-4=four; Path=/restricted/\r\n",
+ &Cookie{Name: "cookie-1", Value: "v$1"},
+ "cookie-1=v$1",
+ },
+ {
+ &Cookie{Name: "cookie-2", Value: "two", MaxAge: 3600},
+ "cookie-2=two; Max-Age=3600",
+ },
+ {
+ &Cookie{Name: "cookie-3", Value: "three", Domain: ".example.com"},
+ "cookie-3=three; Domain=.example.com",
+ },
+ {
+ &Cookie{Name: "cookie-4", Value: "four", Path: "/restricted/"},
+ "cookie-4=four; Path=/restricted/",
},
}
func TestWriteSetCookies(t *testing.T) {
for i, tt := range writeSetCookiesTests {
- var w bytes.Buffer
- writeSetCookies(&w, tt.Cookies)
- seen := string(w.Bytes())
- if seen != tt.Raw {
- t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, seen)
+ if g, e := tt.Cookie.String(), tt.Raw; g != e {
+ t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, e, g)
continue
}
}
}
-var writeCookiesTests = []struct {
+type headerOnlyResponseWriter Header
+
+func (ho headerOnlyResponseWriter) Header() Header {
+ return Header(ho)
+}
+
+func (ho headerOnlyResponseWriter) Write([]byte) (int, os.Error) {
+ panic("NOIMPL")
+}
+
+func (ho headerOnlyResponseWriter) WriteHeader(int) {
+ panic("NOIMPL")
+}
+
+func TestSetCookie(t *testing.T) {
+ m := make(Header)
+ SetCookie(headerOnlyResponseWriter(m), &Cookie{Name: "cookie-1", Value: "one", Path: "/restricted/"})
+ SetCookie(headerOnlyResponseWriter(m), &Cookie{Name: "cookie-2", Value: "two", MaxAge: 3600})
+ if l := len(m["Set-Cookie"]); l != 2 {
+ t.Fatalf("expected %d cookies, got %d", 2, l)
+ }
+ if g, e := m["Set-Cookie"][0], "cookie-1=one; Path=/restricted/"; g != e {
+ t.Errorf("cookie #1: want %q, got %q", e, g)
+ }
+ if g, e := m["Set-Cookie"][1], "cookie-2=two; Max-Age=3600"; g != e {
+ t.Errorf("cookie #2: want %q, got %q", e, g)
+ }
+}
+
+var addCookieTests = []struct {
Cookies []*Cookie
Raw string
}{
{
+ []*Cookie{},
+ "",
+ },
+ {
[]*Cookie{&Cookie{Name: "cookie-1", Value: "v$1"}},
- "Cookie: cookie-1=v$1\r\n",
+ "cookie-1=v$1",
+ },
+ {
+ []*Cookie{
+ &Cookie{Name: "cookie-1", Value: "v$1"},
+ &Cookie{Name: "cookie-2", Value: "v$2"},
+ &Cookie{Name: "cookie-3", Value: "v$3"},
+ },
+ "cookie-1=v$1; cookie-2=v$2; cookie-3=v$3",
},
}
-func TestWriteCookies(t *testing.T) {
- for i, tt := range writeCookiesTests {
- var w bytes.Buffer
- writeCookies(&w, tt.Cookies)
- seen := string(w.Bytes())
- if seen != tt.Raw {
- t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, seen)
+func TestAddCookie(t *testing.T) {
+ for i, tt := range addCookieTests {
+ req, _ := NewRequest("GET", "http://example.com/", nil)
+ for _, c := range tt.Cookies {
+ req.AddCookie(c)
+ }
+ if g := req.Header.Get("Cookie"); g != tt.Raw {
+ t.Errorf("Test %d:\nwant: %s\n got: %s\n", i, tt.Raw, g)
continue
}
}
@@ -73,6 +116,19 @@ var readSetCookiesTests = []struct {
Header{"Set-Cookie": {"Cookie-1=v$1"}},
[]*Cookie{&Cookie{Name: "Cookie-1", Value: "v$1", Raw: "Cookie-1=v$1"}},
},
+ {
+ Header{"Set-Cookie": {"NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly"}},
+ []*Cookie{&Cookie{
+ Name: "NID",
+ Value: "99=YsDT5i3E-CXax-",
+ Path: "/",
+ Domain: ".google.ch",
+ HttpOnly: true,
+ Expires: time.Time{Year: 2011, Month: 11, Day: 23, Hour: 1, Minute: 5, Second: 3, Weekday: 3, ZoneOffset: 0, Zone: "GMT"},
+ RawExpires: "Wed, 23-Nov-2011 01:05:03 GMT",
+ Raw: "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
+ }},
+ },
}
func toJSON(v interface{}) string {
@@ -85,30 +141,61 @@ func toJSON(v interface{}) string {
func TestReadSetCookies(t *testing.T) {
for i, tt := range readSetCookiesTests {
- c := readSetCookies(tt.Header)
- if !reflect.DeepEqual(c, tt.Cookies) {
- t.Errorf("#%d readSetCookies: have\n%s\nwant\n%s\n", i, toJSON(c), toJSON(tt.Cookies))
- continue
+ for n := 0; n < 2; n++ { // to verify readSetCookies doesn't mutate its input
+ c := readSetCookies(tt.Header)
+ if !reflect.DeepEqual(c, tt.Cookies) {
+ t.Errorf("#%d readSetCookies: have\n%s\nwant\n%s\n", i, toJSON(c), toJSON(tt.Cookies))
+ continue
+ }
}
}
}
var readCookiesTests = []struct {
Header Header
+ Filter string
Cookies []*Cookie
}{
{
- Header{"Cookie": {"Cookie-1=v$1"}},
- []*Cookie{&Cookie{Name: "Cookie-1", Value: "v$1"}},
+ Header{"Cookie": {"Cookie-1=v$1", "c2=v2"}},
+ "",
+ []*Cookie{
+ &Cookie{Name: "Cookie-1", Value: "v$1"},
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1", "c2=v2"}},
+ "c2",
+ []*Cookie{
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1; c2=v2"}},
+ "",
+ []*Cookie{
+ &Cookie{Name: "Cookie-1", Value: "v$1"},
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1; c2=v2"}},
+ "c2",
+ []*Cookie{
+ &Cookie{Name: "c2", Value: "v2"},
+ },
},
}
func TestReadCookies(t *testing.T) {
for i, tt := range readCookiesTests {
- c := readCookies(tt.Header)
- if !reflect.DeepEqual(c, tt.Cookies) {
- t.Errorf("#%d readCookies: have\n%s\nwant\n%s\n", i, toJSON(c), toJSON(tt.Cookies))
- continue
+ for n := 0; n < 2; n++ { // to verify readCookies doesn't mutate its input
+ c := readCookies(tt.Header, tt.Filter)
+ if !reflect.DeepEqual(c, tt.Cookies) {
+ t.Errorf("#%d readCookies:\nhave: %s\nwant: %s\n", i, toJSON(c), toJSON(tt.Cookies))
+ continue
+ }
}
}
}
diff --git a/libgo/go/http/fs.go b/libgo/go/http/fs.go
index 17d5297b82c..2c7c636fda0 100644
--- a/libgo/go/http/fs.go
+++ b/libgo/go/http/fs.go
@@ -11,6 +11,7 @@ import (
"io"
"mime"
"os"
+ "path"
"path/filepath"
"strconv"
"strings"
@@ -18,6 +19,38 @@ import (
"utf8"
)
+// A Dir implements http.FileSystem using the native file
+// system restricted to a specific directory tree.
+type Dir string
+
+func (d Dir) Open(name string) (File, os.Error) {
+ if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 {
+ return nil, os.NewError("http: invalid character in file path")
+ }
+ f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name))))
+ if err != nil {
+ return nil, err
+ }
+ return f, nil
+}
+
+// A FileSystem implements access to a collection of named files.
+// The elements in a file path are separated by slash ('/', U+002F)
+// characters, regardless of host operating system convention.
+type FileSystem interface {
+ Open(name string) (File, os.Error)
+}
+
+// A File is returned by a FileSystem's Open method and can be
+// served by the FileServer implementation.
+type File interface {
+ Close() os.Error
+ Stat() (*os.FileInfo, os.Error)
+ Readdir(count int) ([]os.FileInfo, os.Error)
+ Read([]byte) (int, os.Error)
+ Seek(offset int64, whence int) (int64, os.Error)
+}
+
// 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 {
@@ -44,7 +77,8 @@ func isText(b []byte) bool {
return true
}
-func dirList(w ResponseWriter, f *os.File) {
+func dirList(w ResponseWriter, f File) {
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, "<pre>\n")
for {
dirs, err := f.Readdir(100)
@@ -63,16 +97,19 @@ func dirList(w ResponseWriter, f *os.File) {
fmt.Fprintf(w, "</pre>\n")
}
-func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
+// name is '/'-separated, not filepath.Separator.
+func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
const indexPage = "/index.html"
// redirect .../index.html to .../
+ // can't use Redirect() because that would make the path absolute,
+ // which would be a problem running under StripPrefix
if strings.HasSuffix(r.URL.Path, indexPage) {
- Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
+ localRedirect(w, r, "./")
return
}
- f, err := os.Open(name)
+ f, err := fs.Open(name)
if err != nil {
// TODO expose actual error?
NotFound(w, r)
@@ -93,12 +130,12 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
url := r.URL.Path
if d.IsDirectory() {
if url[len(url)-1] != '/' {
- Redirect(w, r, url+"/", StatusMovedPermanently)
+ localRedirect(w, r, path.Base(url)+"/")
return
}
} else {
if url[len(url)-1] == '/' {
- Redirect(w, r, url[0:len(url)-1], StatusMovedPermanently)
+ localRedirect(w, r, "../"+path.Base(url))
return
}
}
@@ -112,8 +149,8 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
// use contents of index.html for directory, if present
if d.IsDirectory() {
- index := name + filepath.FromSlash(indexPage)
- ff, err := os.Open(index)
+ index := name + indexPage
+ ff, err := fs.Open(index)
if err == nil {
defer ff.Close()
dd, err := ff.Stat()
@@ -157,7 +194,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
// TODO(adg): handle multiple ranges
ranges, err := parseRange(r.Header.Get("Range"), size)
if err == nil && len(ranges) > 1 {
- err = os.ErrorString("multiple ranges not supported")
+ err = os.NewError("multiple ranges not supported")
}
if err != nil {
Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
@@ -175,7 +212,9 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
}
w.Header().Set("Accept-Ranges", "bytes")
- w.Header().Set("Content-Length", strconv.Itoa64(size))
+ if w.Header().Get("Content-Encoding") == "" {
+ w.Header().Set("Content-Length", strconv.Itoa64(size))
+ }
w.WriteHeader(code)
@@ -184,30 +223,44 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
}
}
+// localRedirect gives a Moved Permanently response.
+// It does not convert relative paths to absolute paths like Redirect does.
+func localRedirect(w ResponseWriter, r *Request, newPath string) {
+ if q := r.URL.RawQuery; q != "" {
+ newPath += "?" + q
+ }
+ w.Header().Set("Location", newPath)
+ w.WriteHeader(StatusMovedPermanently)
+}
+
// 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)
+ dir, file := filepath.Split(name)
+ serveFile(w, r, Dir(dir), file, false)
}
type fileHandler struct {
- root string
- prefix string
+ root FileSystem
}
// 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} }
+//
+// To use the operating system's file system implementation,
+// use http.Dir:
+//
+// http.Handle("/", http.FileServer(http.Dir("/tmp")))
+func FileServer(root FileSystem) Handler {
+ return &fileHandler{root}
+}
func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
- path := r.URL.Path
- if !strings.HasPrefix(path, f.prefix) {
- NotFound(w, r)
- return
+ upath := r.URL.Path
+ if !strings.HasPrefix(upath, "/") {
+ upath = "/" + upath
+ r.URL.Path = upath
}
- path = path[len(f.prefix):]
- serveFile(w, r, filepath.Join(f.root, filepath.FromSlash(path)), true)
+ serveFile(w, r, f.root, path.Clean(upath), true)
}
// httpRange specifies the byte range to be sent to the client.
@@ -225,7 +278,7 @@ func parseRange(s string, size int64) ([]httpRange, os.Error) {
return nil, os.NewError("invalid range")
}
var ranges []httpRange
- for _, ra := range strings.Split(s[len(b):], ",", -1) {
+ for _, ra := range strings.Split(s[len(b):], ",") {
i := strings.Index(ra, "-")
if i < 0 {
return nil, os.NewError("invalid range")
diff --git a/libgo/go/http/fs_test.go b/libgo/go/http/fs_test.go
index 09d0981f26e..bb6d0158b7b 100644
--- a/libgo/go/http/fs_test.go
+++ b/libgo/go/http/fs_test.go
@@ -10,7 +10,10 @@ import (
"http/httptest"
"io/ioutil"
"os"
+ "path/filepath"
+ "strings"
"testing"
+ "url"
)
const (
@@ -47,7 +50,7 @@ func TestServeFile(t *testing.T) {
// set up the Request (re-used for all tests)
var req Request
req.Header = make(Header)
- if req.URL, err = ParseURL(ts.URL); err != nil {
+ if req.URL, err = url.Parse(ts.URL); err != nil {
t.Fatal("ParseURL:", err)
}
req.Method = "GET"
@@ -85,6 +88,126 @@ func TestServeFile(t *testing.T) {
}
}
+var fsRedirectTestData = []struct {
+ original, redirect string
+}{
+ {"/test/index.html", "/test/"},
+ {"/test/testdata", "/test/testdata/"},
+ {"/test/testdata/file/", "/test/testdata/file"},
+}
+
+func TestFSRedirect(t *testing.T) {
+ ts := httptest.NewServer(StripPrefix("/test", FileServer(Dir("."))))
+ defer ts.Close()
+
+ for _, data := range fsRedirectTestData {
+ res, err := Get(ts.URL + data.original)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ if g, e := res.Request.URL.Path, data.redirect; g != e {
+ t.Errorf("redirect from %s: got %s, want %s", data.original, g, e)
+ }
+ }
+}
+
+type testFileSystem struct {
+ open func(name string) (File, os.Error)
+}
+
+func (fs *testFileSystem) Open(name string) (File, os.Error) {
+ return fs.open(name)
+}
+
+func TestFileServerCleans(t *testing.T) {
+ ch := make(chan string, 1)
+ fs := FileServer(&testFileSystem{func(name string) (File, os.Error) {
+ ch <- name
+ return nil, os.ENOENT
+ }})
+ tests := []struct {
+ reqPath, openArg string
+ }{
+ {"/foo.txt", "/foo.txt"},
+ {"//foo.txt", "/foo.txt"},
+ {"/../foo.txt", "/foo.txt"},
+ }
+ req, _ := NewRequest("GET", "http://example.com", nil)
+ for n, test := range tests {
+ rec := httptest.NewRecorder()
+ req.URL.Path = test.reqPath
+ fs.ServeHTTP(rec, req)
+ if got := <-ch; got != test.openArg {
+ t.Errorf("test %d: got %q, want %q", n, got, test.openArg)
+ }
+ }
+}
+
+func TestFileServerImplicitLeadingSlash(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("TempDir: %v", err)
+ }
+ defer os.RemoveAll(tempDir)
+ if err := ioutil.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ }
+ ts := httptest.NewServer(StripPrefix("/bar/", FileServer(Dir(tempDir))))
+ defer ts.Close()
+ get := func(suffix string) string {
+ res, err := Get(ts.URL + suffix)
+ if err != nil {
+ t.Fatalf("Get %s: %v", suffix, err)
+ }
+ b, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("ReadAll %s: %v", suffix, err)
+ }
+ return string(b)
+ }
+ if s := get("/bar/"); !strings.Contains(s, ">foo.txt<") {
+ t.Logf("expected a directory listing with foo.txt, got %q", s)
+ }
+ if s := get("/bar/foo.txt"); s != "Hello world" {
+ t.Logf("expected %q, got %q", "Hello world", s)
+ }
+}
+
+func TestDirJoin(t *testing.T) {
+ wfi, err := os.Stat("/etc/hosts")
+ if err != nil {
+ t.Logf("skipping test; no /etc/hosts file")
+ return
+ }
+ test := func(d Dir, name string) {
+ f, err := d.Open(name)
+ if err != nil {
+ t.Fatalf("open of %s: %v", name, err)
+ }
+ defer f.Close()
+ gfi, err := f.Stat()
+ if err != nil {
+ t.Fatalf("stat of %s: %v", name, err)
+ }
+ if gfi.Ino != wfi.Ino {
+ t.Errorf("%s got different inode", name)
+ }
+ }
+ test(Dir("/etc/"), "/hosts")
+ test(Dir("/etc/"), "hosts")
+ test(Dir("/etc/"), "../../../../hosts")
+ test(Dir("/etc"), "/hosts")
+ test(Dir("/etc"), "hosts")
+ test(Dir("/etc"), "../../../../hosts")
+
+ // Not really directories, but since we use this trick in
+ // ServeFile, test it:
+ test(Dir("/etc/hosts"), "")
+ test(Dir("/etc/hosts"), "/")
+ test(Dir("/etc/hosts"), "../")
+}
+
func TestServeFileContentType(t *testing.T) {
const ctype = "icecream/chocolate"
override := false
@@ -96,7 +219,7 @@ func TestServeFileContentType(t *testing.T) {
}))
defer ts.Close()
get := func(want string) {
- resp, _, err := Get(ts.URL)
+ resp, err := Get(ts.URL)
if err != nil {
t.Fatal(err)
}
@@ -109,6 +232,57 @@ func TestServeFileContentType(t *testing.T) {
get(ctype)
}
+func TestServeFileMimeType(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "testdata/style.css")
+ }))
+ defer ts.Close()
+ resp, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "text/css; charset=utf-8"
+ if h := resp.Header.Get("Content-Type"); h != want {
+ t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
+ }
+}
+
+func TestServeFileWithContentEncoding(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Encoding", "foo")
+ ServeFile(w, r, "testdata/file")
+ }))
+ defer ts.Close()
+ resp, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := resp.ContentLength, int64(-1); g != e {
+ t.Errorf("Content-Length mismatch: got %d, want %d", g, e)
+ }
+}
+
+func TestServeIndexHtml(t *testing.T) {
+ const want = "index.html says hello\n"
+ ts := httptest.NewServer(FileServer(Dir(".")))
+ defer ts.Close()
+
+ for _, path := range []string{"/testdata/", "/testdata/index.html"} {
+ res, err := Get(ts.URL + path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ b, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal("reading Body:", err)
+ }
+ if s := string(b); s != want {
+ t.Errorf("for path %q got %q, want %q", path, s, want)
+ }
+ }
+}
+
func getBody(t *testing.T, req Request) (*Response, []byte) {
r, err := DefaultClient.Do(&req)
if err != nil {
diff --git a/libgo/go/http/header.go b/libgo/go/http/header.go
index 95140b01f2a..08b07713041 100644
--- a/libgo/go/http/header.go
+++ b/libgo/go/http/header.go
@@ -56,15 +56,12 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) os.Error {
keys = append(keys, k)
}
}
- sort.SortStrings(keys)
+ sort.Strings(keys)
for _, k := range keys {
for _, v := range h[k] {
v = strings.Replace(v, "\n", " ", -1)
v = strings.Replace(v, "\r", " ", -1)
v = strings.TrimSpace(v)
- if v == "" {
- continue
- }
if _, err := fmt.Fprintf(w, "%s: %s\r\n", k, v); err != nil {
return err
}
diff --git a/libgo/go/http/header_test.go b/libgo/go/http/header_test.go
index 7e24cb069c6..ccdee8a97bd 100644
--- a/libgo/go/http/header_test.go
+++ b/libgo/go/http/header_test.go
@@ -57,6 +57,16 @@ var headerWriteTests = []struct {
map[string]bool{"Content-Length": true, "Expires": true, "Content-Encoding": true},
"",
},
+ {
+ Header{
+ "Nil": nil,
+ "Empty": {},
+ "Blank": {""},
+ "Double-Blank": {"", ""},
+ },
+ nil,
+ "Blank: \r\nDouble-Blank: \r\nDouble-Blank: \r\n",
+ },
}
func TestHeaderWrite(t *testing.T) {
diff --git a/libgo/go/http/httptest/server.go b/libgo/go/http/httptest/server.go
index 8e385d045a1..2ec36d04cf6 100644
--- a/libgo/go/http/httptest/server.go
+++ b/libgo/go/http/httptest/server.go
@@ -9,6 +9,7 @@ package httptest
import (
"crypto/rand"
"crypto/tls"
+ "flag"
"fmt"
"http"
"net"
@@ -49,15 +50,34 @@ func newLocalListener() net.Listener {
return l
}
+// When debugging a particular http server-based test,
+// this flag lets you run
+// gotest -run=BrokenTest -httptest.serve=127.0.0.1:8000
+// to start the broken server so you can interact with it manually.
+var serve = flag.String("httptest.serve", "", "if non-empty, httptest.NewServer serves on this address and blocks")
+
// NewServer starts and returns a new Server.
// The caller should call Close when finished, to shut it down.
func NewServer(handler http.Handler) *Server {
ts := new(Server)
- l := newLocalListener()
+ var l net.Listener
+ if *serve != "" {
+ var err os.Error
+ l, err = net.Listen("tcp", *serve)
+ if err != nil {
+ panic(fmt.Sprintf("httptest: failed to listen on %v: %v", *serve, err))
+ }
+ } else {
+ l = newLocalListener()
+ }
ts.Listener = &historyListener{l, make([]net.Conn, 0)}
ts.URL = "http://" + l.Addr().String()
server := &http.Server{Handler: handler}
go server.Serve(ts.Listener)
+ if *serve != "" {
+ fmt.Println(os.Stderr, "httptest: serving on", ts.URL)
+ select {}
+ }
return ts
}
@@ -108,29 +128,24 @@ func (s *Server) CloseClientConnections() {
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
// of ASN.1 time).
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
-MIIBwTCCASugAwIBAgIBADALBgkqhkiG9w0BAQUwADAeFw0xMTAzMzEyMDI1MDda
-Fw00OTEyMzEyMzU5NTlaMAAwggCdMAsGCSqGSIb3DQEBAQOCAIwAMIIAhwKCAIB6
-oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZLKq2sM3gRaimsktIw
-nNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0SjdZ7vTPnFDPNsHGe
-KBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBA6NPME0wDgYDVR0PAQH/
-BAQDAgCgMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwGwYDVR0RBBQw
-EoIJMTI3LjAuMC4xggVbOjoxXTALBgkqhkiG9w0BAQUDggCBAHC3gbdvc44vs+wD
-g2kONiENnx8WKc0UTGg/TOXS3gaRb+CUIQtHWja65l8rAfclEovjHgZ7gx8brO0W
-JuC6p3MUAKsgOssIrrRIx2rpnfcmFVMzguCmrMNVmKUAalw18Yp0F72xYAIitVQl
-kJrLdIhBajcJRYu/YGltHQRaXuVt
+MIIBOTCB5qADAgECAgEAMAsGCSqGSIb3DQEBBTAAMB4XDTcwMDEwMTAwMDAwMFoX
+DTQ5MTIzMTIzNTk1OVowADBaMAsGCSqGSIb3DQEBAQNLADBIAkEAsuA5mAFMj6Q7
+qoBzcvKzIq4kzuT5epSp2AkcQfyBHm7K13Ws7u+0b5Vb9gqTf5cAiIKcrtrXVqkL
+8i1UQF6AzwIDAQABo08wTTAOBgNVHQ8BAf8EBAMCACQwDQYDVR0OBAYEBAECAwQw
+DwYDVR0jBAgwBoAEAQIDBDAbBgNVHREEFDASggkxMjcuMC4wLjGCBVs6OjFdMAsG
+CSqGSIb3DQEBBQNBAJH30zjLWRztrWpOCgJL8RQWLaKzhK79pVhAx6q/3NrF16C7
++l1BRZstTwIGdoGId8BRpErK1TXkniFb95ZMynM=
-----END CERTIFICATE-----
`)
// localhostKey is the private key for localhostCert.
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
-MIIBkgIBAQKCAIB6oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZL
-Kq2sM3gRaimsktIwnNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0S
-jdZ7vTPnFDPNsHGeKBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBAwKC
-AIBRwh7Bil5Z8cYpZZv7jdQxDvbim7Z7ocRdeDmzZuF2I9RW04QyHHPIIlALnBvI
-YeF1veASz1gEFGUjzmbUGqKYSbCoTzXoev+F4bmbRxcX9sOmtslqvhMSHRSzA5NH
-aDVI3Hn4wvBVD8gePu8ACWqvPGbCiql11OKCMfjlPn2uuwJAx/24/F5DjXZ6hQQ7
-HxScOxKrpx5WnA9r1wZTltOTZkhRRzuLc21WJeE3M15QUdWi3zZxCKRFoth65HEs
-jy9YHQJAnPueRI44tz79b5QqVbeaOMUr7ZCb1Kp0uo6G+ANPLdlfliAupwij2eIz
-mHRJOWk0jBtXfRft1McH2H51CpXAyw==
+MIIBPQIBAAJBALLgOZgBTI+kO6qAc3LysyKuJM7k+XqUqdgJHEH8gR5uytd1rO7v
+tG+VW/YKk3+XAIiCnK7a11apC/ItVEBegM8CAwEAAQJBAI5sxq7naeR9ahyqRkJi
+SIv2iMxLuPEHaezf5CYOPWjSjBPyVhyRevkhtqEjF/WkgL7C2nWpYHsUcBDBQVF0
+3KECIQDtEGB2ulnkZAahl3WuJziXGLB+p8Wgx7wzSM6bHu1c6QIhAMEp++CaS+SJ
+/TrU0zwY/fW4SvQeb49BPZUF3oqR8Xz3AiEA1rAJHBzBgdOQKdE3ksMUPcnvNJSN
+poCcELmz2clVXtkCIQCLytuLV38XHToTipR4yMl6O+6arzAjZ56uq7m7ZRV0TwIh
+AM65XAOw8Dsg9Kq78aYXiOEDc5DL0sbFUu/SlmRcCg93
-----END RSA PRIVATE KEY-----
`)
diff --git a/libgo/go/http/persist.go b/libgo/go/http/persist.go
index e4eea6815d0..78bf9058f3c 100644
--- a/libgo/go/http/persist.go
+++ b/libgo/go/http/persist.go
@@ -24,6 +24,9 @@ var (
// to regain 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.
+//
+// ServerConn is low-level and should not be needed by most applications.
+// See Server.
type ServerConn struct {
lk sync.Mutex // read-write protects the following fields
c net.Conn
@@ -111,7 +114,7 @@ func (sc *ServerConn) Read() (req *Request, err os.Error) {
// Make sure body is fully consumed, even if user does not call body.Close
if lastbody != nil {
// body.Close is assumed to be idempotent and multiple calls to
- // it should return the error that its first invokation
+ // it should return the error that its first invocation
// returned.
err = lastbody.Close()
if err != nil {
@@ -211,6 +214,9 @@ func (sc *ServerConn) Write(req *Request, resp *Response) os.Error {
// connection, while respecting the HTTP keepalive logic. ClientConn
// supports hijacking the connection calling Hijack to
// regain control of the underlying net.Conn and deal with it as desired.
+//
+// ClientConn is low-level and should not be needed by most applications.
+// See Client.
type ClientConn struct {
lk sync.Mutex // read-write protects the following fields
c net.Conn
@@ -222,7 +228,6 @@ type ClientConn struct {
pipe textproto.Pipeline
writeReq func(*Request, io.Writer) os.Error
- readRes func(buf *bufio.Reader, method string) (*Response, os.Error)
}
// NewClientConn returns a new ClientConn reading and writing c. If r is not
@@ -236,7 +241,6 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
r: r,
pipereq: make(map[*Request]uint),
writeReq: (*Request).Write,
- readRes: ReadResponse,
}
}
@@ -339,8 +343,13 @@ func (cc *ClientConn) Pending() int {
// 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(req *Request) (resp *Response, err os.Error) {
+func (cc *ClientConn) Read(req *Request) (*Response, os.Error) {
+ return cc.readUsing(req, ReadResponse)
+}
+// readUsing is the implementation of Read with a replaceable
+// ReadResponse-like function, used by the Transport.
+func (cc *ClientConn) readUsing(req *Request, readRes func(*bufio.Reader, *Request) (*Response, os.Error)) (resp *Response, err os.Error) {
// Retrieve the pipeline ID of this request/response pair
cc.lk.Lock()
id, ok := cc.pipereq[req]
@@ -383,7 +392,7 @@ func (cc *ClientConn) Read(req *Request) (resp *Response, err os.Error) {
}
}
- resp, err = cc.readRes(r, req.Method)
+ resp, err = readRes(r, req)
cc.lk.Lock()
defer cc.lk.Unlock()
if err != nil {
diff --git a/libgo/go/http/proxy_test.go b/libgo/go/http/proxy_test.go
index 308bf44b48a..9b320b3aa5b 100644
--- a/libgo/go/http/proxy_test.go
+++ b/libgo/go/http/proxy_test.go
@@ -40,10 +40,8 @@ func TestUseProxy(t *testing.T) {
no_proxy := "foobar.com, .barbaz.net"
os.Setenv("NO_PROXY", no_proxy)
- tr := &Transport{}
-
for _, test := range UseProxyTests {
- if tr.useProxy(test.host+":80") != test.match {
+ if useProxy(test.host+":80") != test.match {
t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
}
}
diff --git a/libgo/go/http/readrequest_test.go b/libgo/go/http/readrequest_test.go
index 19e2ff77476..f6dc99e2e08 100644
--- a/libgo/go/http/readrequest_test.go
+++ b/libgo/go/http/readrequest_test.go
@@ -10,14 +10,19 @@ import (
"fmt"
"io"
"testing"
+ "url"
)
type reqTest struct {
- Raw string
- Req Request
- Body string
+ Raw string
+ Req *Request
+ Body string
+ Error string
}
+var noError = ""
+var noBody = ""
+
var reqTests = []reqTest{
// Baseline test; All Request fields included for template use
{
@@ -33,10 +38,10 @@ var reqTests = []reqTest{
"Proxy-Connection: keep-alive\r\n\r\n" +
"abcdef\n???",
- Request{
+ &Request{
Method: "GET",
RawURL: "http://www.techcrunch.com/",
- URL: &URL{
+ URL: &url.URL{
Raw: "http://www.techcrunch.com/",
Scheme: "http",
RawPath: "/",
@@ -58,16 +63,43 @@ var reqTests = []reqTest{
"Keep-Alive": {"300"},
"Proxy-Connection": {"keep-alive"},
"Content-Length": {"7"},
+ "User-Agent": {"Fake"},
},
Close: false,
ContentLength: 7,
Host: "www.techcrunch.com",
- Referer: "",
- UserAgent: "Fake",
- Form: map[string][]string{},
+ Form: url.Values{},
},
"abcdef\n",
+
+ noError,
+ },
+
+ // GET request with no body (the normal case)
+ {
+ "GET / HTTP/1.1\r\n" +
+ "Host: foo.com\r\n\r\n",
+
+ &Request{
+ Method: "GET",
+ RawURL: "/",
+ URL: &url.URL{
+ Raw: "/",
+ Path: "/",
+ RawPath: "/",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Close: false,
+ ContentLength: 0,
+ Host: "foo.com",
+ Form: url.Values{},
+ },
+
+ noBody,
+ noError,
},
// Tests that we don't parse a path that looks like a
@@ -76,10 +108,10 @@ var reqTests = []reqTest{
"GET //user@host/is/actually/a/path/ HTTP/1.1\r\n" +
"Host: test\r\n\r\n",
- Request{
+ &Request{
Method: "GET",
RawURL: "//user@host/is/actually/a/path/",
- URL: &URL{
+ URL: &url.URL{
Raw: "//user@host/is/actually/a/path/",
Scheme: "",
RawPath: "//user@host/is/actually/a/path/",
@@ -95,14 +127,31 @@ var reqTests = []reqTest{
ProtoMinor: 1,
Header: Header{},
Close: false,
- ContentLength: -1,
+ ContentLength: 0,
Host: "test",
- Referer: "",
- UserAgent: "",
- Form: map[string][]string{},
+ Form: url.Values{},
},
- "",
+ noBody,
+ noError,
+ },
+
+ // Tests a bogus abs_path on the Request-Line (RFC 2616 section 5.1.2)
+ {
+ "GET ../../../../etc/passwd HTTP/1.1\r\n" +
+ "Host: test\r\n\r\n",
+ nil,
+ noBody,
+ "parse ../../../../etc/passwd: invalid URI for request",
+ },
+
+ // Tests missing URL:
+ {
+ "GET HTTP/1.1\r\n" +
+ "Host: test\r\n\r\n",
+ nil,
+ noBody,
+ "parse : empty url",
},
}
@@ -113,12 +162,14 @@ func TestReadRequest(t *testing.T) {
braw.WriteString(tt.Raw)
req, err := ReadRequest(bufio.NewReader(&braw))
if err != nil {
- t.Errorf("#%d: %s", i, err)
+ if err.String() != tt.Error {
+ t.Errorf("#%d: error %q, want error %q", i, err.String(), tt.Error)
+ }
continue
}
rbody := req.Body
req.Body = nil
- diff(t, fmt.Sprintf("#%d Request", i), req, &tt.Req)
+ diff(t, fmt.Sprintf("#%d Request", i), req, tt.Req)
var bout bytes.Buffer
if rbody != nil {
io.Copy(&bout, rbody)
diff --git a/libgo/go/http/request.go b/libgo/go/http/request.go
index 8545d75660a..ed41fa45c13 100644
--- a/libgo/go/http/request.go
+++ b/libgo/go/http/request.go
@@ -10,8 +10,9 @@ package http
import (
"bufio"
+ "bytes"
"crypto/tls"
- "container/vector"
+ "encoding/base64"
"fmt"
"io"
"io/ioutil"
@@ -21,6 +22,7 @@ import (
"os"
"strconv"
"strings"
+ "url"
)
const (
@@ -33,13 +35,15 @@ const (
// ErrMissingFile is returned by FormFile when the provided file field name
// is either not present in the request or not a file field.
-var ErrMissingFile = os.ErrorString("http: no such file")
+var ErrMissingFile = os.NewError("http: no such file")
// HTTP request parsing errors.
type ProtocolError struct {
- os.ErrorString
+ ErrorString string
}
+func (err *ProtocolError) String() string { return err.ErrorString }
+
var (
ErrLineTooLong = &ProtocolError{"header line too long"}
ErrHeaderTooLong = &ProtocolError{"header too long"}
@@ -58,10 +62,10 @@ type badStringError struct {
func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e.str) }
-var reqExcludeHeader = map[string]bool{
+// Headers that Request.Write handles itself and should be skipped.
+var reqWriteExcludeHeader = map[string]bool{
"Host": true,
"User-Agent": true,
- "Referer": true,
"Content-Length": true,
"Transfer-Encoding": true,
"Trailer": true,
@@ -69,9 +73,9 @@ var reqExcludeHeader = map[string]bool{
// 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.
+ Method string // GET, POST, PUT, etc.
+ RawURL string // The raw URL given in the request.
+ URL *url.URL // Parsed URL.
// The protocol version for incoming requests.
// Outgoing requests always use HTTP/1.1.
@@ -88,10 +92,10 @@ type Request struct {
//
// then
//
- // Header = map[string]string{
- // "Accept-Encoding": "gzip, deflate",
- // "Accept-Language": "en-us",
- // "Connection": "keep-alive",
+ // Header = map[string][]string{
+ // "Accept-Encoding": {"gzip, deflate"},
+ // "Accept-Language": {"en-us"},
+ // "Connection": {"keep-alive"},
// }
//
// HTTP defines that header names are case-insensitive.
@@ -100,9 +104,6 @@ type Request struct {
// following a hyphen uppercase and the rest lowercase.
Header Header
- // Cookie records the HTTP cookies sent with the request.
- Cookie []*Cookie
-
// The message body.
Body io.ReadCloser
@@ -123,23 +124,8 @@ type Request struct {
// or the host name given in the URL itself.
Host string
- // The referring URL, if sent in the request.
- //
- // Referer is misspelled as in the request itself,
- // a mistake from the earliest days of HTTP.
- // This value can also be fetched from the Header map
- // as Header["Referer"]; the benefit of making it
- // available as a structure field is that the compiler
- // can diagnose programs that use the alternate
- // (correct English) spelling req.Referrer but cannot
- // diagnose programs that use Header["Referrer"].
- Referer string
-
- // The User-Agent: header string, if sent in the request.
- UserAgent string
-
// The parsed form. Only available after ParseForm is called.
- Form map[string][]string
+ Form url.Values
// The parsed multipart form, including file uploads.
// Only available after ParseMultipartForm is called.
@@ -174,6 +160,52 @@ func (r *Request) ProtoAtLeast(major, minor int) bool {
r.ProtoMajor == major && r.ProtoMinor >= minor
}
+// UserAgent returns the client's User-Agent, if sent in the request.
+func (r *Request) UserAgent() string {
+ return r.Header.Get("User-Agent")
+}
+
+// Cookies parses and returns the HTTP cookies sent with the request.
+func (r *Request) Cookies() []*Cookie {
+ return readCookies(r.Header, "")
+}
+
+var ErrNoCookie = os.NewError("http: named cookied not present")
+
+// Cookie returns the named cookie provided in the request or
+// ErrNoCookie if not found.
+func (r *Request) Cookie(name string) (*Cookie, os.Error) {
+ for _, c := range readCookies(r.Header, name) {
+ return c, nil
+ }
+ return nil, ErrNoCookie
+}
+
+// AddCookie adds a cookie to the request. Per RFC 6265 section 5.4,
+// AddCookie does not attach more than one Cookie header field. That
+// means all cookies, if any, are written into the same line,
+// separated by semicolon.
+func (r *Request) AddCookie(c *Cookie) {
+ s := fmt.Sprintf("%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
+ if c := r.Header.Get("Cookie"); c != "" {
+ r.Header.Set("Cookie", c+"; "+s)
+ } else {
+ r.Header.Set("Cookie", s)
+ }
+}
+
+// Referer returns the referring URL, if sent in the request.
+//
+// Referer is misspelled as in the request itself, a mistake from the
+// earliest days of HTTP. This value can also be fetched from the
+// Header map as Header["Referer"]; the benefit of making it available
+// as a method is that the compiler can diagnose programs that use the
+// alternate (correct English) spelling req.Referrer() but cannot
+// diagnose programs that use Header["Referrer"].
+func (r *Request) Referer() string {
+ return r.Header.Get("Referer")
+}
+
// multipartByReader is a sentinel value.
// Its presence in Request.MultipartForm indicates that parsing of the request
// body has been handed off to a MultipartReader instead of ParseMultipartFrom.
@@ -186,7 +218,7 @@ var multipartByReader = &multipart.Form{
// multipart/form-data POST request, else returns nil and an error.
// Use this function instead of ParseMultipartForm to
// process the request body as a stream.
-func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
+func (r *Request) MultipartReader() (*multipart.Reader, os.Error) {
if r.MultipartForm == multipartByReader {
return nil, os.NewError("http: MultipartReader called twice")
}
@@ -197,7 +229,7 @@ func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
return r.multipartReader()
}
-func (r *Request) multipartReader() (multipart.Reader, os.Error) {
+func (r *Request) multipartReader() (*multipart.Reader, os.Error) {
v := r.Header.Get("Content-Type")
if v == "" {
return nil, ErrNotMultipart
@@ -228,17 +260,14 @@ const defaultUserAgent = "Go http package"
// Host
// RawURL, if non-empty, or else URL
// Method (defaults to "GET")
-// UserAgent (defaults to defaultUserAgent)
-// Referer
// Header
-// Cookie
// ContentLength
// TransferEncoding
// Body
//
-// If Body is present but Content-Length is <= 0, Write adds
-// "Transfer-Encoding: chunked" to the header. Body is closed after
-// it is sent.
+// If Body is present, Content-Length is <= 0 and TransferEncoding
+// hasn't been set to "identity", Write adds "Transfer-Encoding:
+// chunked" to the header. Body is closed after it is sent.
func (req *Request) Write(w io.Writer) os.Error {
return req.write(w, false)
}
@@ -255,32 +284,42 @@ func (req *Request) WriteProxy(w io.Writer) os.Error {
func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
host := req.Host
if host == "" {
+ if req.URL == nil {
+ return os.NewError("http: Request.Write on Request with no Host or URL set")
+ }
host = req.URL.Host
}
- uri := req.RawURL
- if uri == "" {
- uri = valueOrDefault(urlEscape(req.URL.Path, encodePath), "/")
+ urlStr := req.RawURL
+ if urlStr == "" {
+ urlStr = valueOrDefault(req.URL.EncodedPath(), "/")
if req.URL.RawQuery != "" {
- uri += "?" + req.URL.RawQuery
+ urlStr += "?" + req.URL.RawQuery
}
if usingProxy {
- if uri == "" || uri[0] != '/' {
- uri = "/" + uri
+ if urlStr == "" || urlStr[0] != '/' {
+ urlStr = "/" + urlStr
}
- uri = req.URL.Scheme + "://" + host + uri
+ urlStr = req.URL.Scheme + "://" + host + urlStr
}
}
- fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), uri)
+ bw := bufio.NewWriter(w)
+ fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), urlStr)
// Header lines
- if !usingProxy {
- fmt.Fprintf(w, "Host: %s\r\n", host)
+ fmt.Fprintf(bw, "Host: %s\r\n", host)
+
+ // Use the defaultUserAgent unless the Header contains one, which
+ // may be blank to not send the header.
+ userAgent := defaultUserAgent
+ if req.Header != nil {
+ if ua := req.Header["User-Agent"]; len(ua) > 0 {
+ userAgent = ua[0]
+ }
}
- fmt.Fprintf(w, "User-Agent: %s\r\n", valueOrDefault(req.UserAgent, defaultUserAgent))
- if req.Referer != "" {
- fmt.Fprintf(w, "Referer: %s\r\n", req.Referer)
+ if userAgent != "" {
+ fmt.Fprintf(bw, "User-Agent: %s\r\n", userAgent)
}
// Process Body,ContentLength,Close,Trailer
@@ -288,35 +327,25 @@ func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
if err != nil {
return err
}
- err = tw.WriteHeader(w)
+ err = tw.WriteHeader(bw)
if err != nil {
return err
}
// TODO: split long values? (If so, should share code with Conn.Write)
- // TODO: if Header includes values for Host, User-Agent, or Referer, this
- // may conflict with the User-Agent or Referer headers we add manually.
- // One solution would be to remove the Host, UserAgent, and Referer fields
- // from Request, and introduce Request methods along the lines of
- // Response.{GetHeader,AddHeader} and string constants for "Host",
- // "User-Agent" and "Referer".
- err = req.Header.WriteSubset(w, reqExcludeHeader)
+ err = req.Header.WriteSubset(bw, reqWriteExcludeHeader)
if err != nil {
return err
}
- if err = writeCookies(w, req.Cookie); err != nil {
- return err
- }
-
- io.WriteString(w, "\r\n")
+ io.WriteString(bw, "\r\n")
// Write body and trailer
- err = tw.WriteBody(w)
+ err = tw.WriteBody(bw)
if err != nil {
return err
}
-
+ bw.Flush()
return nil
}
@@ -399,10 +428,6 @@ type chunkedReader struct {
err os.Error
}
-func newChunkedReader(r *bufio.Reader) *chunkedReader {
- return &chunkedReader{r: r}
-}
-
func (cr *chunkedReader) beginChunk() {
// chunk-size CRLF
var line string
@@ -457,8 +482,8 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err os.Error) {
}
// NewRequest returns a new Request given a method, URL, and optional body.
-func NewRequest(method, url string, body io.Reader) (*Request, os.Error) {
- u, err := ParseURL(url)
+func NewRequest(method, urlStr string, body io.Reader) (*Request, os.Error) {
+ u, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
@@ -476,9 +501,28 @@ func NewRequest(method, url string, body io.Reader) (*Request, os.Error) {
Body: rc,
Host: u.Host,
}
+ if body != nil {
+ switch v := body.(type) {
+ case *strings.Reader:
+ req.ContentLength = int64(v.Len())
+ case *bytes.Buffer:
+ req.ContentLength = int64(v.Len())
+ }
+ }
+
return req, nil
}
+// SetBasicAuth sets the request's Authorization header to use HTTP
+// Basic Authentication with the provided username and password.
+//
+// With HTTP Basic Authentication the provided username and password
+// are not encrypted.
+func (r *Request) SetBasicAuth(username, password string) {
+ s := username + ":" + password
+ r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(s)))
+}
+
// ReadRequest reads and parses a request from b.
func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
@@ -495,7 +539,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
}
var f []string
- if f = strings.Split(s, " ", 3); len(f) < 3 {
+ if f = strings.SplitN(s, " ", 3); len(f) < 3 {
return nil, &badStringError{"malformed HTTP request", s}
}
req.Method, req.RawURL, req.Proto = f[0], f[1], f[2]
@@ -504,7 +548,7 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
return nil, &badStringError{"malformed HTTP version", req.Proto}
}
- if req.URL, err = ParseRequestURL(req.RawURL); err != nil {
+ if req.URL, err = url.ParseRequest(req.RawURL); err != nil {
return nil, err
}
@@ -530,13 +574,6 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
fixPragmaCacheControl(req.Header)
- // Pull out useful fields as a convenience to clients.
- req.Referer = req.Header.Get("Referer")
- req.Header.Del("Referer")
-
- req.UserAgent = req.Header.Get("User-Agent")
- req.Header.Del("User-Agent")
-
// TODO: Parse specific header values:
// Accept
// Accept-Encoding
@@ -568,46 +605,9 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
return nil, err
}
- req.Cookie = readCookies(req.Header)
-
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 raw query.
// For POST requests, it also parses the request body as a form.
// ParseMultipartForm calls ParseForm automatically.
@@ -617,16 +617,15 @@ func (r *Request) ParseForm() (err os.Error) {
return
}
- r.Form = make(map[string][]string)
if r.URL != nil {
- err = parseQuery(r.Form, r.URL.RawQuery)
+ r.Form, err = url.ParseQuery(r.URL.RawQuery)
}
if r.Method == "POST" {
if r.Body == nil {
- return os.ErrorString("missing form body")
+ return os.NewError("missing form body")
}
ct := r.Header.Get("Content-Type")
- switch strings.Split(ct, ";", 2)[0] {
+ switch strings.SplitN(ct, ";", 2)[0] {
case "text/plain", "application/x-www-form-urlencoded", "":
const maxFormSize = int64(10 << 20) // 10 MB is a lot of text.
b, e := ioutil.ReadAll(io.LimitReader(r.Body, maxFormSize+1))
@@ -639,10 +638,20 @@ func (r *Request) ParseForm() (err os.Error) {
if int64(len(b)) > maxFormSize {
return os.NewError("http: POST too large")
}
- e = parseQuery(r.Form, string(b))
+ var newValues url.Values
+ newValues, e = url.ParseQuery(string(b))
if err == nil {
err = e
}
+ if r.Form == nil {
+ r.Form = make(url.Values)
+ }
+ // Copy values into r.Form. TODO: make this smoother.
+ for k, vs := range newValues {
+ for _, value := range vs {
+ r.Form.Add(k, value)
+ }
+ }
case "multipart/form-data":
// handled by ParseMultipartForm
default:
@@ -659,6 +668,9 @@ func (r *Request) ParseForm() (err os.Error) {
// ParseMultipartForm calls ParseForm if necessary.
// After one call to ParseMultipartForm, subsequent calls have no effect.
func (r *Request) ParseMultipartForm(maxMemory int64) os.Error {
+ if r.MultipartForm == multipartByReader {
+ return os.NewError("http: multipart handled by MultipartReader")
+ }
if r.Form == nil {
err := r.ParseForm()
if err != nil {
@@ -668,9 +680,6 @@ func (r *Request) ParseMultipartForm(maxMemory int64) os.Error {
if r.MultipartForm != nil {
return nil
}
- if r.MultipartForm == multipartByReader {
- return os.NewError("http: multipart handled by MultipartReader")
- }
mr, err := r.multipartReader()
if err == ErrNotMultipart {
diff --git a/libgo/go/http/request_test.go b/libgo/go/http/request_test.go
index f79d3a24240..869cd57b696 100644
--- a/libgo/go/http/request_test.go
+++ b/libgo/go/http/request_test.go
@@ -17,6 +17,7 @@ import (
"regexp"
"strings"
"testing"
+ "url"
)
type stringMultimap map[string][]string
@@ -43,7 +44,7 @@ var parseTests = []parseTest{
func TestParseForm(t *testing.T) {
for i, test := range parseTests {
- form, err := ParseQuery(test.query)
+ form, err := url.ParseQuery(test.query)
if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err)
continue
@@ -72,7 +73,7 @@ func TestParseForm(t *testing.T) {
func TestQuery(t *testing.T) {
req := &Request{Method: "GET"}
- req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar")
+ req.URL, _ = url.Parse("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)
}
@@ -80,7 +81,7 @@ func TestQuery(t *testing.T) {
func TestPostQuery(t *testing.T) {
req := &Request{Method: "POST"}
- req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar&both=x")
+ req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar&both=x")
req.Header = Header{
"Content-Type": {"application/x-www-form-urlencoded; boo!"},
}
@@ -162,16 +163,25 @@ func TestRedirect(t *testing.T) {
defer ts.Close()
var end = regexp.MustCompile("/foo/$")
- r, url, err := Get(ts.URL)
+ r, err := Get(ts.URL)
if err != nil {
t.Fatal(err)
}
r.Body.Close()
+ url := r.Request.URL.String()
if r.StatusCode != 200 || !end.MatchString(url) {
t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url)
}
}
+func TestSetBasicAuth(t *testing.T) {
+ r, _ := NewRequest("GET", "http://example.com/", nil)
+ r.SetBasicAuth("Aladdin", "open sesame")
+ if g, e := r.Header.Get("Authorization"), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; g != e {
+ t.Errorf("got header %q, want %q", g, e)
+ }
+}
+
func TestMultipartRequest(t *testing.T) {
// Test that we can read the values and files of a
// multipart request with FormValue and FormFile,
@@ -210,16 +220,28 @@ func TestEmptyMultipartRequest(t *testing.T) {
testMissingFile(t, req)
}
+func TestRequestMultipartCallOrder(t *testing.T) {
+ req := newTestMultipartRequest(t)
+ _, err := req.MultipartReader()
+ if err != nil {
+ t.Fatalf("MultipartReader: %v", err)
+ }
+ err = req.ParseMultipartForm(1024)
+ if err == nil {
+ t.Errorf("expected an error from ParseMultipartForm after call to MultipartReader")
+ }
+}
+
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {
- t.Errorf("FormFile file = %q, want nil", f, nil)
+ t.Errorf("FormFile file = %q, want nil", f)
}
if fh != nil {
- t.Errorf("FormFile file header = %q, want nil", fh, nil)
+ t.Errorf("FormFile file header = %q, want nil", fh)
}
if err != ErrMissingFile {
- t.Errorf("FormFile err = %q, want nil", err, ErrMissingFile)
+ t.Errorf("FormFile err = %q, want ErrMissingFile", err)
}
}
@@ -227,7 +249,7 @@ func newTestMultipartRequest(t *testing.T) *Request {
b := bytes.NewBufferString(strings.Replace(message, "\n", "\r\n", -1))
req, err := NewRequest("POST", "/", b)
if err != nil {
- t.Fatalf("NewRequest:", err)
+ t.Fatal("NewRequest:", err)
}
ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary)
req.Header.Set("Content-type", ctype)
@@ -267,7 +289,7 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File {
f, fh, err := req.FormFile(key)
if err != nil {
- t.Fatalf("FormFile(%q):", key, err)
+ t.Fatalf("FormFile(%q): %q", key, err)
}
if fh.Filename != expectFilename {
t.Errorf("filename = %q, want %q", fh.Filename, expectFilename)
diff --git a/libgo/go/http/requestwrite_test.go b/libgo/go/http/requestwrite_test.go
index bb000c701ff..458f0bd7f4b 100644
--- a/libgo/go/http/requestwrite_test.go
+++ b/libgo/go/http/requestwrite_test.go
@@ -6,16 +6,18 @@ package http
import (
"bytes"
+ "fmt"
"io"
"io/ioutil"
"os"
"strings"
"testing"
+ "url"
)
type reqWriteTest struct {
Req Request
- Body []byte
+ Body interface{} // optional []byte or func() io.ReadCloser to populate Req.Body
Raw string
RawProxy string
}
@@ -26,7 +28,7 @@ var reqWriteTests = []reqWriteTest{
Request{
Method: "GET",
RawURL: "http://www.techcrunch.com/",
- URL: &URL{
+ URL: &url.URL{
Raw: "http://www.techcrunch.com/",
Scheme: "http",
RawPath: "http://www.techcrunch.com/",
@@ -47,13 +49,12 @@ var reqWriteTests = []reqWriteTest{
"Accept-Language": {"en-us,en;q=0.5"},
"Keep-Alive": {"300"},
"Proxy-Connection": {"keep-alive"},
+ "User-Agent": {"Fake"},
},
- Body: nil,
- Close: false,
- Host: "www.techcrunch.com",
- Referer: "",
- UserAgent: "Fake",
- Form: map[string][]string{},
+ Body: nil,
+ Close: false,
+ Host: "www.techcrunch.com",
+ Form: map[string][]string{},
},
nil,
@@ -69,6 +70,7 @@ var reqWriteTests = []reqWriteTest{
"Proxy-Connection: keep-alive\r\n\r\n",
"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-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
@@ -81,7 +83,7 @@ var reqWriteTests = []reqWriteTest{
{
Request{
Method: "GET",
- URL: &URL{
+ URL: &url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/search",
@@ -98,18 +100,19 @@ var reqWriteTests = []reqWriteTest{
"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",
+ chunk("abcdef") + chunk(""),
"GET http://www.google.com/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",
+ chunk("abcdef") + chunk(""),
},
// HTTP/1.1 POST => chunked coding; body; empty trailer
{
Request{
Method: "POST",
- URL: &URL{
+ URL: &url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/search",
@@ -128,20 +131,21 @@ var reqWriteTests = []reqWriteTest{
"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",
+ chunk("abcdef") + chunk(""),
"POST http://www.google.com/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",
+ chunk("abcdef") + chunk(""),
},
// HTTP/1.1 POST with Content-Length, no chunking
{
Request{
Method: "POST",
- URL: &URL{
+ URL: &url.URL{
Scheme: "http",
Host: "www.google.com",
Path: "/search",
@@ -164,6 +168,7 @@ var reqWriteTests = []reqWriteTest{
"abcdef",
"POST http://www.google.com/search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
"User-Agent: Go http package\r\n" +
"Connection: close\r\n" +
"Content-Length: 6\r\n" +
@@ -171,6 +176,35 @@ var reqWriteTests = []reqWriteTest{
"abcdef",
},
+ // HTTP/1.1 POST with Content-Length in headers
+ {
+ Request{
+ Method: "POST",
+ RawURL: "http://example.com/",
+ Host: "example.com",
+ Header: Header{
+ "Content-Length": []string{"10"}, // ignored
+ },
+ ContentLength: 6,
+ },
+
+ []byte("abcdef"),
+
+ "POST http://example.com/ HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Content-Length: 6\r\n" +
+ "\r\n" +
+ "abcdef",
+
+ "POST http://example.com/ HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Content-Length: 6\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
+
// default to HTTP/1.1
{
Request{
@@ -188,16 +222,79 @@ var reqWriteTests = []reqWriteTest{
// Looks weird but RawURL overrides what WriteProxy would choose.
"GET /search HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
"User-Agent: Go http package\r\n" +
"\r\n",
},
+
+ // Request with a 0 ContentLength and a 0 byte body.
+ {
+ Request{
+ Method: "POST",
+ RawURL: "/",
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) },
+
+ "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "\r\n",
+
+ "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "\r\n",
+ },
+
+ // Request with a 0 ContentLength and a 1 byte body.
+ {
+ Request{
+ Method: "POST",
+ RawURL: "/",
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 1)) },
+
+ "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("x") + chunk(""),
+
+ "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ chunk("x") + chunk(""),
+ },
}
func TestRequestWrite(t *testing.T) {
for i := range reqWriteTests {
tt := &reqWriteTests[i]
+
+ setBody := func() {
+ switch b := tt.Body.(type) {
+ case []byte:
+ tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+ case func() io.ReadCloser:
+ tt.Req.Body = b()
+ }
+ }
if tt.Body != nil {
- tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(tt.Body))
+ setBody()
+ }
+ if tt.Req.Header == nil {
+ tt.Req.Header = make(Header)
}
var braw bytes.Buffer
err := tt.Req.Write(&braw)
@@ -212,7 +309,7 @@ func TestRequestWrite(t *testing.T) {
}
if tt.Body != nil {
- tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(tt.Body))
+ setBody()
}
var praw bytes.Buffer
err = tt.Req.WriteProxy(&praw)
@@ -240,13 +337,34 @@ func (rc *closeChecker) Close() os.Error {
// TestRequestWriteClosesBody tests that Request.Write does close its request.Body.
// It also indirectly tests NewRequest and that it doesn't wrap an existing Closer
-// inside a NopCloser.
+// inside a NopCloser, and that it serializes it correctly.
func TestRequestWriteClosesBody(t *testing.T) {
rc := &closeChecker{Reader: strings.NewReader("my body")}
- req, _ := NewRequest("GET", "http://foo.com/", rc)
+ req, _ := NewRequest("POST", "http://foo.com/", rc)
+ if req.ContentLength != 0 {
+ t.Errorf("got req.ContentLength %d, want 0", req.ContentLength)
+ }
buf := new(bytes.Buffer)
req.Write(buf)
if !rc.closed {
t.Error("body not closed after write")
}
+ expected := "POST / HTTP/1.1\r\n" +
+ "Host: foo.com\r\n" +
+ "User-Agent: Go http package\r\n" +
+ "Transfer-Encoding: chunked\r\n\r\n" +
+ // TODO: currently we don't buffer before chunking, so we get a
+ // single "m" chunk before the other chunks, as this was the 1-byte
+ // read from our MultiReader where we stiched the Body back together
+ // after sniffing whether the Body was 0 bytes or not.
+ chunk("m") +
+ chunk("y body") +
+ chunk("")
+ if buf.String() != expected {
+ t.Errorf("write:\n got: %s\nwant: %s", buf.String(), expected)
+ }
+}
+
+func chunk(s string) string {
+ return fmt.Sprintf("%x\r\n%s\r\n", len(s), s)
}
diff --git a/libgo/go/http/response.go b/libgo/go/http/response.go
index a65c2b14df6..915327a69ec 100644
--- a/libgo/go/http/response.go
+++ b/libgo/go/http/response.go
@@ -30,10 +30,6 @@ type Response struct {
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
@@ -44,9 +40,6 @@ type Response struct {
// Keys in the map are canonicalized (see CanonicalHeaderKey).
Header Header
- // SetCookie records the Set-Cookie requests sent with the response.
- SetCookie []*Cookie
-
// Body represents the response body.
Body io.ReadCloser
@@ -68,19 +61,31 @@ type Response struct {
// Trailer maps trailer keys to values, in the same
// format as the header.
Trailer Header
+
+ // The Request that was sent to obtain this Response.
+ // Request's Body is nil (having already been consumed).
+ // This is only populated for Client requests.
+ Request *Request
+}
+
+// Cookies parses and returns the cookies set in the Set-Cookie headers.
+func (r *Response) Cookies() []*Cookie {
+ return readSetCookies(r.Header)
}
-// ReadResponse reads and returns an HTTP response from r. The 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) {
+// ReadResponse reads and returns an HTTP response from r. The
+// req parameter specifies the Request that corresponds to
+// this Response. Clients must call resp.Body.Close when finished
+// 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, req *Request) (resp *Response, err os.Error) {
tp := textproto.NewReader(r)
resp = new(Response)
- resp.RequestMethod = strings.ToUpper(requestMethod)
+ resp.Request = req
+ resp.Request.Method = strings.ToUpper(resp.Request.Method)
// Parse the first line of the response.
line, err := tp.ReadLine()
@@ -90,7 +95,7 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os
}
return nil, err
}
- f := strings.Split(line, " ", 3)
+ f := strings.SplitN(line, " ", 3)
if len(f) < 2 {
return nil, &badStringError{"malformed HTTP response", line}
}
@@ -124,8 +129,6 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os
return nil, err
}
- resp.SetCookie = readSetCookies(resp.Header)
-
return resp, nil
}
@@ -164,7 +167,9 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
func (resp *Response) Write(w io.Writer) os.Error {
// RequestMethod should be upper-case
- resp.RequestMethod = strings.ToUpper(resp.RequestMethod)
+ if resp.Request != nil {
+ resp.Request.Method = strings.ToUpper(resp.Request.Method)
+ }
// Status line
text := resp.Status
@@ -195,10 +200,6 @@ func (resp *Response) Write(w io.Writer) os.Error {
return err
}
- if err = writeSetCookies(w, resp.SetCookie); err != nil {
- return err
- }
-
// End-of-header
io.WriteString(w, "\r\n")
diff --git a/libgo/go/http/response_test.go b/libgo/go/http/response_test.go
index 9e77c20c40b..1d4a2342358 100644
--- a/libgo/go/http/response_test.go
+++ b/libgo/go/http/response_test.go
@@ -23,6 +23,10 @@ type respTest struct {
Body string
}
+func dummyReq(method string) *Request {
+ return &Request{Method: method}
+}
+
var respTests = []respTest{
// Unchunked response without Content-Length.
{
@@ -32,12 +36,12 @@ var respTests = []respTest{
"Body here\n",
Response{
- Status: "200 OK",
- StatusCode: 200,
- Proto: "HTTP/1.0",
- ProtoMajor: 1,
- ProtoMinor: 0,
- RequestMethod: "GET",
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
Header: Header{
"Connection": {"close"}, // TODO(rsc): Delete?
},
@@ -61,7 +65,7 @@ var respTests = []respTest{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Close: true,
ContentLength: -1,
},
@@ -81,7 +85,7 @@ var respTests = []respTest{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Close: false,
ContentLength: 0,
},
@@ -98,12 +102,12 @@ var respTests = []respTest{
"Body here\n",
Response{
- Status: "200 OK",
- StatusCode: 200,
- Proto: "HTTP/1.0",
- ProtoMajor: 1,
- ProtoMinor: 0,
- RequestMethod: "GET",
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
Header: Header{
"Connection": {"close"}, // TODO(rsc): Delete?
"Content-Length": {"10"}, // TODO(rsc): Delete?
@@ -133,7 +137,7 @@ var respTests = []respTest{
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Header: Header{},
Close: true,
ContentLength: -1,
@@ -160,7 +164,7 @@ var respTests = []respTest{
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Header: Header{},
Close: true,
ContentLength: -1, // TODO(rsc): Fix?
@@ -183,7 +187,7 @@ var respTests = []respTest{
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
- RequestMethod: "HEAD",
+ Request: dummyReq("HEAD"),
Header: Header{},
Close: true,
ContentLength: 0,
@@ -199,12 +203,12 @@ var respTests = []respTest{
"\r\n",
Response{
- Status: "200 OK",
- StatusCode: 200,
- Proto: "HTTP/1.1",
- ProtoMajor: 1,
- ProtoMinor: 1,
- RequestMethod: "GET",
+ Status: "200 OK",
+ StatusCode: 200,
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
Header: Header{
"Content-Length": {"0"},
},
@@ -225,7 +229,7 @@ var respTests = []respTest{
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Header: Header{},
Close: true,
ContentLength: -1,
@@ -244,7 +248,7 @@ var respTests = []respTest{
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Header: Header{},
Close: true,
ContentLength: -1,
@@ -259,7 +263,7 @@ func TestReadResponse(t *testing.T) {
tt := &respTests[i]
var braw bytes.Buffer
braw.WriteString(tt.Raw)
- resp, err := ReadResponse(bufio.NewReader(&braw), tt.Resp.RequestMethod)
+ resp, err := ReadResponse(bufio.NewReader(&braw), tt.Resp.Request)
if err != nil {
t.Errorf("#%d: %s", i, err)
continue
@@ -340,7 +344,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
buf.WriteString("Next Request Here")
bufr := bufio.NewReader(&buf)
- resp, err := ReadResponse(bufr, "GET")
+ resp, err := ReadResponse(bufr, dummyReq("GET"))
checkErr(err, "ReadResponse")
expectedLength := int64(-1)
if !test.chunked {
@@ -372,7 +376,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
rest, err := ioutil.ReadAll(bufr)
checkErr(err, "ReadAll on remainder")
if e, g := "Next Request Here", string(rest); e != g {
- fatalf("for chunked=%v remainder = %q, expected %q", g, e)
+ fatalf("remainder = %q, expected %q", g, e)
}
}
}
@@ -381,7 +385,7 @@ func diff(t *testing.T, prefix string, have, want interface{}) {
hv := reflect.ValueOf(have).Elem()
wv := reflect.ValueOf(want).Elem()
if hv.Type() != wv.Type() {
- t.Errorf("%s: type mismatch %v vs %v", prefix, hv.Type(), wv.Type())
+ t.Errorf("%s: type mismatch %v want %v", prefix, hv.Type(), wv.Type())
}
for i := 0; i < hv.NumField(); i++ {
hf := hv.Field(i).Interface()
diff --git a/libgo/go/http/responsewrite_test.go b/libgo/go/http/responsewrite_test.go
index de0635da516..f8e63acf4f7 100644
--- a/libgo/go/http/responsewrite_test.go
+++ b/libgo/go/http/responsewrite_test.go
@@ -22,7 +22,7 @@ var respWriteTests = []respWriteTest{
StatusCode: 503,
ProtoMajor: 1,
ProtoMinor: 0,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Header: Header{},
Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
ContentLength: 6,
@@ -38,7 +38,7 @@ var respWriteTests = []respWriteTest{
StatusCode: 200,
ProtoMajor: 1,
ProtoMinor: 0,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Header: Header{},
Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
ContentLength: -1,
@@ -53,7 +53,7 @@ var respWriteTests = []respWriteTest{
StatusCode: 200,
ProtoMajor: 1,
ProtoMinor: 1,
- RequestMethod: "GET",
+ Request: dummyReq("GET"),
Header: Header{},
Body: ioutil.NopCloser(bytes.NewBufferString("abcdef")),
ContentLength: 6,
@@ -71,10 +71,10 @@ var respWriteTests = []respWriteTest{
// Also tests removal of leading and trailing whitespace.
{
Response{
- StatusCode: 204,
- ProtoMajor: 1,
- ProtoMinor: 1,
- RequestMethod: "GET",
+ StatusCode: 204,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Request: dummyReq("GET"),
Header: Header{
"Foo": []string{" Bar\nBaz "},
},
diff --git a/libgo/go/http/reverseproxy.go b/libgo/go/http/reverseproxy.go
index e4ce1e34c79..3f8bfdc80c2 100644
--- a/libgo/go/http/reverseproxy.go
+++ b/libgo/go/http/reverseproxy.go
@@ -10,7 +10,11 @@ import (
"io"
"log"
"net"
+ "os"
"strings"
+ "sync"
+ "time"
+ "url"
)
// ReverseProxy is an HTTP Handler that takes an incoming request and
@@ -26,6 +30,12 @@ type ReverseProxy struct {
// The Transport used to perform proxy requests.
// If nil, DefaultTransport is used.
Transport RoundTripper
+
+ // FlushInterval specifies the flush interval, in
+ // nanoseconds, to flush to the client while
+ // coping the response body.
+ // If zero, no periodic flushing is done.
+ FlushInterval int64
}
func singleJoiningSlash(a, b string) string {
@@ -44,7 +54,7 @@ func singleJoiningSlash(a, b string) string {
// URLs to the scheme, host, and base path provided in target. If the
// target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir.
-func NewSingleHostReverseProxy(target *URL) *ReverseProxy {
+func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
director := func(req *Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
@@ -95,6 +105,55 @@ func (p *ReverseProxy) ServeHTTP(rw ResponseWriter, req *Request) {
rw.WriteHeader(res.StatusCode)
if res.Body != nil {
- io.Copy(rw, res.Body)
+ var dst io.Writer = rw
+ if p.FlushInterval != 0 {
+ if wf, ok := rw.(writeFlusher); ok {
+ dst = &maxLatencyWriter{dst: wf, latency: p.FlushInterval}
+ }
+ }
+ io.Copy(dst, res.Body)
+ }
+}
+
+type writeFlusher interface {
+ io.Writer
+ Flusher
+}
+
+type maxLatencyWriter struct {
+ dst writeFlusher
+ latency int64 // nanos
+
+ lk sync.Mutex // protects init of done, as well Write + Flush
+ done chan bool
+}
+
+func (m *maxLatencyWriter) Write(p []byte) (n int, err os.Error) {
+ m.lk.Lock()
+ defer m.lk.Unlock()
+ if m.done == nil {
+ m.done = make(chan bool)
+ go m.flushLoop()
+ }
+ n, err = m.dst.Write(p)
+ if err != nil {
+ m.done <- true
+ }
+ return
+}
+
+func (m *maxLatencyWriter) flushLoop() {
+ t := time.NewTicker(m.latency)
+ defer t.Stop()
+ for {
+ select {
+ case <-t.C:
+ m.lk.Lock()
+ m.dst.Flush()
+ m.lk.Unlock()
+ case <-m.done:
+ return
+ }
}
+ panic("unreached")
}
diff --git a/libgo/go/http/reverseproxy_test.go b/libgo/go/http/reverseproxy_test.go
index 8cf7705d745..8078c8d10df 100644
--- a/libgo/go/http/reverseproxy_test.go
+++ b/libgo/go/http/reverseproxy_test.go
@@ -11,21 +11,29 @@ import (
"http/httptest"
"io/ioutil"
"testing"
+ "url"
)
func TestReverseProxy(t *testing.T) {
const backendResponse = "I am the backend"
const backendStatus = 404
backend := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if len(r.TransferEncoding) > 0 {
+ t.Errorf("backend got unexpected TransferEncoding: %v", r.TransferEncoding)
+ }
if r.Header.Get("X-Forwarded-For") == "" {
t.Errorf("didn't get X-Forwarded-For header")
}
+ if g, e := r.Host, "some-name"; g != e {
+ t.Errorf("backend got Host header %q, want %q", g, e)
+ }
w.Header().Set("X-Foo", "bar")
+ SetCookie(w, &Cookie{Name: "flavor", Value: "chocolateChip"})
w.WriteHeader(backendStatus)
w.Write([]byte(backendResponse))
}))
defer backend.Close()
- backendURL, err := ParseURL(backend.URL)
+ backendURL, err := url.Parse(backend.URL)
if err != nil {
t.Fatal(err)
}
@@ -33,7 +41,9 @@ func TestReverseProxy(t *testing.T) {
frontend := httptest.NewServer(proxyHandler)
defer frontend.Close()
- res, _, err := Get(frontend.URL)
+ getReq, _ := NewRequest("GET", frontend.URL, nil)
+ getReq.Host = "some-name"
+ res, err := DefaultClient.Do(getReq)
if err != nil {
t.Fatalf("Get: %v", err)
}
@@ -43,6 +53,12 @@ func TestReverseProxy(t *testing.T) {
if g, e := res.Header.Get("X-Foo"), "bar"; g != e {
t.Errorf("got X-Foo %q; expected %q", g, e)
}
+ if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
+ t.Fatalf("got %d SetCookies, want %d", g, e)
+ }
+ if cookie := res.Cookies()[0]; cookie.Name != "flavor" {
+ t.Errorf("unexpected cookie %q", cookie.Name)
+ }
bodyBytes, _ := ioutil.ReadAll(res.Body)
if g, e := string(bodyBytes), backendResponse; g != e {
t.Errorf("got body %q; expected %q", g, e)
diff --git a/libgo/go/http/serve_test.go b/libgo/go/http/serve_test.go
index 7ff6ef04b1a..ac040334596 100644
--- a/libgo/go/http/serve_test.go
+++ b/libgo/go/http/serve_test.go
@@ -12,13 +12,17 @@ import (
"fmt"
. "http"
"http/httptest"
+ "io"
"io/ioutil"
+ "log"
"os"
"net"
"reflect"
"strings"
+ "syscall"
"testing"
"time"
+ "url"
)
type dummyAddr string
@@ -107,7 +111,6 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
listener := &oneConnListener{conn}
handler := func(res ResponseWriter, req *Request) {
reqNum++
- t.Logf("Got request #%d: %v", reqNum, req)
ch <- req
}
@@ -116,7 +119,6 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
}()
var req *Request
- t.Log("Waiting for first request.")
req = <-ch
if req == nil {
t.Fatal("Got nil first request.")
@@ -126,7 +128,6 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
req.Method, "POST")
}
- t.Log("Waiting for second request.")
req = <-ch
if req == nil {
t.Fatal("Got nil first request.")
@@ -136,7 +137,6 @@ func TestConsumingBodyOnNextConn(t *testing.T) {
req.Method, "POST")
}
- t.Log("Waiting for EOF.")
if serveerr := <-servech; serveerr != os.EOF {
t.Errorf("Serve returned %q; expected EOF", serveerr)
}
@@ -184,7 +184,7 @@ func TestHostHandlers(t *testing.T) {
for _, vt := range vtests {
var r *Response
var req Request
- if req.URL, err = ParseURL(vt.url); err != nil {
+ if req.URL, err = url.Parse(vt.url); err != nil {
t.Errorf("cannot parse url: %v", err)
continue
}
@@ -252,7 +252,7 @@ func TestServerTimeouts(t *testing.T) {
// Hit the HTTP server successfully.
tr := &Transport{DisableKeepAlives: true} // they interfere with this test
c := &Client{Transport: tr}
- r, _, err := c.Get(url)
+ r, err := c.Get(url)
if err != nil {
t.Fatalf("http Get #1: %v", err)
}
@@ -282,7 +282,7 @@ func TestServerTimeouts(t *testing.T) {
// Hit the HTTP server successfully again, verifying that the
// previous slow connection didn't run our handler. (that we
// get "req=2", not "req=3")
- r, _, err = Get(url)
+ r, err = Get(url)
if err != nil {
t.Fatalf("http Get #2: %v", err)
}
@@ -323,7 +323,7 @@ func TestIdentityResponse(t *testing.T) {
// responses.
for _, te := range []string{"", "identity"} {
url := ts.URL + "/?te=" + te
- res, _, err := Get(url)
+ res, err := Get(url)
if err != nil {
t.Fatalf("error with Get of %s: %v", url, err)
}
@@ -342,7 +342,7 @@ func TestIdentityResponse(t *testing.T) {
// Verify that ErrContentLength is returned
url := ts.URL + "/?overwrite=1"
- _, _, err := Get(url)
+ _, err := Get(url)
if err != nil {
t.Fatalf("error with Get of %s: %v", url, err)
}
@@ -370,11 +370,8 @@ func TestIdentityResponse(t *testing.T) {
}
}
-// TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
-func TestServeHTTP10Close(t *testing.T) {
- s := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
- ServeFile(w, r, "testdata/file")
- }))
+func testTcpConnectionCloses(t *testing.T, req string, h Handler) {
+ s := httptest.NewServer(h)
defer s.Close()
conn, err := net.Dial("tcp", s.Listener.Addr().String())
@@ -383,13 +380,13 @@ func TestServeHTTP10Close(t *testing.T) {
}
defer conn.Close()
- _, err = fmt.Fprint(conn, "GET / HTTP/1.0\r\n\r\n")
+ _, err = fmt.Fprint(conn, req)
if err != nil {
t.Fatal("print error:", err)
}
r := bufio.NewReader(conn)
- _, err = ReadResponse(r, "GET")
+ _, err = ReadResponse(r, &Request{Method: "GET"})
if err != nil {
t.Fatal("ReadResponse error:", err)
}
@@ -411,13 +408,34 @@ func TestServeHTTP10Close(t *testing.T) {
success <- true
}
+// TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
+func TestServeHTTP10Close(t *testing.T) {
+ testTcpConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "testdata/file")
+ }))
+}
+
+// TestHandlersCanSetConnectionClose verifies that handlers can force a connection to close,
+// even for HTTP/1.1 requests.
+func TestHandlersCanSetConnectionClose11(t *testing.T) {
+ testTcpConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Connection", "close")
+ }))
+}
+
+func TestHandlersCanSetConnectionClose10(t *testing.T) {
+ testTcpConnectionCloses(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Connection", "close")
+ }))
+}
+
func TestSetsRemoteAddr(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%s", r.RemoteAddr)
}))
defer ts.Close()
- res, _, err := Get(ts.URL)
+ res, err := Get(ts.URL)
if err != nil {
t.Fatalf("Get error: %v", err)
}
@@ -432,13 +450,16 @@ func TestSetsRemoteAddr(t *testing.T) {
}
func TestChunkedResponseHeaders(t *testing.T) {
+ log.SetOutput(ioutil.Discard) // is noisy otherwise
+ defer log.SetOutput(os.Stderr)
+
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted
fmt.Fprintf(w, "I am a chunked response.")
}))
defer ts.Close()
- res, _, err := Get(ts.URL)
+ res, err := Get(ts.URL)
if err != nil {
t.Fatalf("Get error: %v", err)
}
@@ -465,7 +486,7 @@ func Test304Responses(t *testing.T) {
}
}))
defer ts.Close()
- res, _, err := Get(ts.URL)
+ res, err := Get(ts.URL)
if err != nil {
t.Error(err)
}
@@ -490,6 +511,12 @@ func TestHeadResponses(t *testing.T) {
if err != ErrBodyNotAllowed {
t.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err)
}
+
+ // Also exercise the ReaderFrom path
+ _, err = io.Copy(w, strings.NewReader("Ignored body"))
+ if err != ErrBodyNotAllowed {
+ t.Errorf("on Copy, expected ErrBodyNotAllowed, got %v", err)
+ }
}))
defer ts.Close()
res, err := Head(ts.URL)
@@ -510,28 +537,30 @@ func TestHeadResponses(t *testing.T) {
func TestTLSServer(t *testing.T) {
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
- fmt.Fprintf(w, "tls=%v", r.TLS != nil)
+ if r.TLS != nil {
+ w.Header().Set("X-TLS-Set", "true")
+ if r.TLS.HandshakeComplete {
+ w.Header().Set("X-TLS-HandshakeComplete", "true")
+ }
+ }
}))
defer ts.Close()
if !strings.HasPrefix(ts.URL, "https://") {
t.Fatalf("expected test TLS server to start with https://, got %q", ts.URL)
}
- res, _, err := Get(ts.URL)
+ res, err := Get(ts.URL)
if err != nil {
- t.Error(err)
+ t.Fatal(err)
}
if res == nil {
t.Fatalf("got nil Response")
}
- if res.Body == nil {
- t.Fatalf("got nil Response.Body")
+ defer res.Body.Close()
+ if res.Header.Get("X-TLS-Set") != "true" {
+ t.Errorf("expected X-TLS-Set response header")
}
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- t.Error(err)
- }
- if e, g := "tls=true", string(body); e != g {
- t.Errorf("expected body %q; got %q", e, g)
+ if res.Header.Get("X-TLS-HandshakeComplete") != "true" {
+ t.Errorf("expected X-TLS-HandshakeComplete header")
}
}
@@ -551,7 +580,7 @@ var serverExpectTests = []serverExpectTest{
{100, "", true, "200 OK"},
// 100-continue but requesting client to deny us,
- // so it never eads the body.
+ // so it never reads the body.
{100, "100-continue", false, "401 Unauthorized"},
// Likewise without 100-continue:
{100, "", false, "401 Unauthorized"},
@@ -624,7 +653,7 @@ func TestServerConsumesRequestBody(t *testing.T) {
"POST / HTTP/1.1\r\n"+
"Host: test\r\n"+
"Content-Length: %d\r\n"+
- "\r\n",len(body))))
+ "\r\n", len(body))))
conn.readBuf.Write([]byte(body))
done := make(chan bool)
@@ -657,7 +686,7 @@ func TestTimeoutHandler(t *testing.T) {
// Succeed without timing out:
sendHi <- true
- res, _, err := Get(ts.URL)
+ res, err := Get(ts.URL)
if err != nil {
t.Error(err)
}
@@ -674,7 +703,7 @@ func TestTimeoutHandler(t *testing.T) {
// Times out:
timeout <- 1
- res, _, err = Get(ts.URL)
+ res, err = Get(ts.URL)
if err != nil {
t.Error(err)
}
@@ -693,3 +722,238 @@ func TestTimeoutHandler(t *testing.T) {
t.Errorf("expected Write error of %v; got %v", e, g)
}
}
+
+// Verifies we don't path.Clean() on the wrong parts in redirects.
+func TestRedirectMunging(t *testing.T) {
+ req, _ := NewRequest("GET", "http://example.com/", nil)
+
+ resp := httptest.NewRecorder()
+ Redirect(resp, req, "/foo?next=http://bar.com/", 302)
+ if g, e := resp.Header().Get("Location"), "/foo?next=http://bar.com/"; g != e {
+ t.Errorf("Location header was %q; want %q", g, e)
+ }
+
+ resp = httptest.NewRecorder()
+ Redirect(resp, req, "http://localhost:8080/_ah/login?continue=http://localhost:8080/", 302)
+ if g, e := resp.Header().Get("Location"), "http://localhost:8080/_ah/login?continue=http://localhost:8080/"; g != e {
+ t.Errorf("Location header was %q; want %q", g, e)
+ }
+}
+
+// TestZeroLengthPostAndResponse exercises an optimization done by the Transport:
+// when there is no body (either because the method doesn't permit a body, or an
+// explicit Content-Length of zero is present), then the transport can re-use the
+// connection immediately. But when it re-uses the connection, it typically closes
+// the previous request's body, which is not optimal for zero-lengthed bodies,
+// as the client would then see http.ErrBodyReadAfterClose and not 0, os.EOF.
+func TestZeroLengthPostAndResponse(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
+ all, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ t.Fatalf("handler ReadAll: %v", err)
+ }
+ if len(all) != 0 {
+ t.Errorf("handler got %d bytes; expected 0", len(all))
+ }
+ rw.Header().Set("Content-Length", "0")
+ }))
+ defer ts.Close()
+
+ req, err := NewRequest("POST", ts.URL, strings.NewReader(""))
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.ContentLength = 0
+
+ var resp [5]*Response
+ for i := range resp {
+ resp[i], err = DefaultClient.Do(req)
+ if err != nil {
+ t.Fatalf("client post #%d: %v", i, err)
+ }
+ }
+
+ for i := range resp {
+ all, err := ioutil.ReadAll(resp[i].Body)
+ if err != nil {
+ t.Fatalf("req #%d: client ReadAll: %v", i, err)
+ }
+ if len(all) != 0 {
+ t.Errorf("req #%d: client got %d bytes; expected 0", i, len(all))
+ }
+ }
+}
+
+func TestHandlerPanic(t *testing.T) {
+ // Unlike the other tests that set the log output to ioutil.Discard
+ // to quiet the output, this test uses a pipe. The pipe serves three
+ // purposes:
+ //
+ // 1) The log.Print from the http server (generated by the caught
+ // panic) will go to the pipe instead of stderr, making the
+ // output quiet.
+ //
+ // 2) We read from the pipe to verify that the handler
+ // actually caught the panic and logged something.
+ //
+ // 3) The blocking Read call prevents this TestHandlerPanic
+ // function from exiting before the HTTP server handler
+ // finishes crashing. If this text function exited too
+ // early (and its defer log.SetOutput(os.Stderr) ran),
+ // then the crash output could spill into the next test.
+ pr, pw := io.Pipe()
+ log.SetOutput(pw)
+ defer log.SetOutput(os.Stderr)
+
+ ts := httptest.NewServer(HandlerFunc(func(ResponseWriter, *Request) {
+ panic("intentional death for testing")
+ }))
+ defer ts.Close()
+ _, err := Get(ts.URL)
+ if err == nil {
+ t.Logf("expected an error")
+ }
+
+ // Do a blocking read on the log output pipe so its logging
+ // doesn't bleed into the next test. But wait only 5 seconds
+ // for it.
+ done := make(chan bool)
+ go func() {
+ buf := make([]byte, 1024)
+ _, err := pr.Read(buf)
+ pr.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ done <- true
+ }()
+ select {
+ case <-done:
+ return
+ case <-time.After(5e9):
+ t.Fatal("expected server handler to log an error")
+ }
+}
+
+func TestNoDate(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header()["Date"] = nil
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, present := res.Header["Date"]
+ if present {
+ t.Fatalf("Expected no Date header; got %v", res.Header["Date"])
+ }
+}
+
+func TestStripPrefix(t *testing.T) {
+ h := HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("X-Path", r.URL.Path)
+ })
+ ts := httptest.NewServer(StripPrefix("/foo", h))
+ defer ts.Close()
+
+ res, err := Get(ts.URL + "/foo/bar")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := res.Header.Get("X-Path"), "/bar"; g != e {
+ t.Errorf("test 1: got %s, want %s", g, e)
+ }
+
+ res, err = Get(ts.URL + "/bar")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, e := res.StatusCode, 404; g != e {
+ t.Errorf("test 2: got status %v, want %v", g, e)
+ }
+}
+
+func TestRequestLimit(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ t.Fatalf("didn't expect to get request in Handler")
+ }))
+ defer ts.Close()
+ req, _ := NewRequest("GET", ts.URL, nil)
+ var bytesPerHeader = len("header12345: val12345\r\n")
+ for i := 0; i < ((DefaultMaxHeaderBytes+4096)/bytesPerHeader)+1; i++ {
+ req.Header.Set(fmt.Sprintf("header%05d", i), fmt.Sprintf("val%05d", i))
+ }
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ // Some HTTP clients may fail on this undefined behavior (server replying and
+ // closing the connection while the request is still being written), but
+ // we do support it (at least currently), so we expect a response below.
+ t.Fatalf("Do: %v", err)
+ }
+ if res.StatusCode != 400 {
+ t.Fatalf("expected 400 response status; got: %d %s", res.StatusCode, res.Status)
+ }
+}
+
+type errorListener struct {
+ errs []os.Error
+}
+
+func (l *errorListener) Accept() (c net.Conn, err os.Error) {
+ if len(l.errs) == 0 {
+ return nil, os.EOF
+ }
+ err = l.errs[0]
+ l.errs = l.errs[1:]
+ return
+}
+
+func (l *errorListener) Close() os.Error {
+ return nil
+}
+
+func (l *errorListener) Addr() net.Addr {
+ return dummyAddr("test-address")
+}
+
+func TestAcceptMaxFds(t *testing.T) {
+ log.SetOutput(ioutil.Discard) // is noisy otherwise
+ defer log.SetOutput(os.Stderr)
+
+ ln := &errorListener{[]os.Error{
+ &net.OpError{
+ Op: "accept",
+ Error: os.Errno(syscall.EMFILE),
+ }}}
+ err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})))
+ if err != os.EOF {
+ t.Errorf("got error %v, want EOF", err)
+ }
+}
+
+func BenchmarkClientServer(b *testing.B) {
+ b.StopTimer()
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
+ fmt.Fprintf(rw, "Hello world.\n")
+ }))
+ defer ts.Close()
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ res, err := Get(ts.URL)
+ if err != nil {
+ panic("Get: " + err.String())
+ }
+ all, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ panic("ReadAll: " + err.String())
+ }
+ body := string(all)
+ if body != "Hello world.\n" {
+ panic("Got body: " + body)
+ }
+ }
+
+ b.StopTimer()
+}
diff --git a/libgo/go/http/server.go b/libgo/go/http/server.go
index d155f06a2d2..b634e27d6df 100644
--- a/libgo/go/http/server.go
+++ b/libgo/go/http/server.go
@@ -6,12 +6,12 @@
// TODO(rsc):
// logging
-// post support
package http
import (
"bufio"
+ "bytes"
"crypto/rand"
"crypto/tls"
"fmt"
@@ -20,10 +20,12 @@ import (
"net"
"os"
"path"
+ "runtime/debug"
"strconv"
"strings"
"sync"
"time"
+ "url"
)
// Errors introduced by the HTTP server.
@@ -93,11 +95,13 @@ type Hijacker interface {
// A conn represents the server side of an HTTP connection.
type conn struct {
remoteAddr string // network address of remote side
- handler Handler // request handler
+ server *Server // the Server on which the connection arrived
rwc net.Conn // i/o connection
- buf *bufio.ReadWriter // buffered rwc
+ lr *io.LimitedReader // io.LimitReader(rwc)
+ buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->rwc
hijacked bool // connection has been hijacked by handler
- tlsState *tls.ConnectionState // or nil when not using TLS
+ tlsState *tls.ConnectionState // or nil when not using TLS
+ body []byte
}
// A response represents the server side of an HTTP response.
@@ -111,6 +115,7 @@ type response struct {
written int64 // number of bytes written in body
contentLength int64 // explicitly-declared Content-Length; or -1
status int // status code passed to WriteHeader
+ needSniff bool // need to sniff to find Content-Type
// close connection after this reply. set on request and
// updated after response from handler if there's a
@@ -119,17 +124,44 @@ type response struct {
closeAfterReply bool
}
+type writerOnly struct {
+ io.Writer
+}
+
+func (r *response) ReadFrom(src io.Reader) (n int64, err os.Error) {
+ // Flush before checking r.chunking, as Flush will call
+ // WriteHeader if it hasn't been called yet, and WriteHeader
+ // is what sets r.chunking.
+ r.Flush()
+ if !r.chunking && r.bodyAllowed() && !r.needSniff {
+ if rf, ok := r.conn.rwc.(io.ReaderFrom); ok {
+ n, err = rf.ReadFrom(src)
+ r.written += n
+ return
+ }
+ }
+ // Fall back to default io.Copy implementation.
+ // Use wrapper to hide r.ReadFrom from io.Copy.
+ return io.Copy(writerOnly{r}, src)
+}
+
+// noLimit is an effective infinite upper bound for io.LimitedReader
+const noLimit int64 = (1 << 63) - 1
+
// Create new connection from rwc.
-func newConn(rwc net.Conn, handler Handler) (c *conn, err os.Error) {
+func (srv *Server) newConn(rwc net.Conn) (c *conn, err os.Error) {
c = new(conn)
c.remoteAddr = rwc.RemoteAddr().String()
- c.handler = handler
+ c.server = srv
c.rwc = rwc
- br := bufio.NewReader(rwc)
+ c.body = make([]byte, sniffLen)
+ c.lr = io.LimitReader(rwc, noLimit).(*io.LimitedReader)
+ br := bufio.NewReader(c.lr)
bw := bufio.NewWriter(rwc)
c.buf = bufio.NewReadWriter(br, bw)
if tlsConn, ok := rwc.(*tls.Conn); ok {
+ tlsConn.Handshake()
c.tlsState = new(tls.ConnectionState)
*c.tlsState = tlsConn.ConnectionState()
}
@@ -137,6 +169,18 @@ func newConn(rwc net.Conn, handler Handler) (c *conn, err os.Error) {
return c, nil
}
+// DefaultMaxHeaderBytes is the maximum permitted size of the headers
+// in an HTTP request.
+// This can be overridden by setting Server.MaxHeaderBytes.
+const DefaultMaxHeaderBytes = 1 << 20 // 1 MB
+
+func (srv *Server) maxHeaderBytes() int {
+ if srv.MaxHeaderBytes > 0 {
+ return srv.MaxHeaderBytes
+ }
+ return DefaultMaxHeaderBytes
+}
+
// wrapper around io.ReaderCloser which on first read, sends an
// HTTP/1.1 100 Continue header
type expectContinueReader struct {
@@ -168,15 +212,22 @@ func (ecr *expectContinueReader) Close() os.Error {
// It is like time.RFC1123 but hard codes GMT as the time zone.
const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
+var errTooLarge = os.NewError("http: request too large")
+
// Read next request from connection.
func (c *conn) readRequest() (w *response, err os.Error) {
if c.hijacked {
return nil, ErrHijacked
}
+ c.lr.N = int64(c.server.maxHeaderBytes()) + 4096 /* bufio slop */
var req *Request
if req, err = ReadRequest(c.buf.Reader); err != nil {
+ if c.lr.N == 0 {
+ return nil, errTooLarge
+ }
return nil, err
}
+ c.lr.N = noLimit
req.RemoteAddr = c.remoteAddr
req.TLS = c.tlsState
@@ -186,6 +237,7 @@ func (c *conn) readRequest() (w *response, err os.Error) {
w.req = req
w.header = make(Header)
w.contentLength = -1
+ c.body = c.body[:0]
return w, nil
}
@@ -226,13 +278,13 @@ func (w *response) WriteHeader(code int) {
}
}
} else {
- // Default output is HTML encoded in UTF-8.
+ // If no content type, apply sniffing algorithm to body.
if w.header.Get("Content-Type") == "" {
- w.header.Set("Content-Type", "text/html; charset=utf-8")
+ w.needSniff = true
}
}
- if w.header.Get("Date") == "" {
+ if _, ok := w.header["Date"]; !ok {
w.Header().Set("Date", time.UTC().Format(TimeFormat))
}
@@ -292,6 +344,10 @@ func (w *response) WriteHeader(code int) {
w.closeAfterReply = true
}
+ if w.header.Get("Connection") == "close" {
+ w.closeAfterReply = true
+ }
+
// Cannot use Content-Length with non-identity Transfer-Encoding.
if w.chunking {
w.header.Del("Content-Length")
@@ -310,7 +366,45 @@ func (w *response) WriteHeader(code int) {
}
io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
w.header.Write(w.conn.buf)
- io.WriteString(w.conn.buf, "\r\n")
+
+ // If we need to sniff the body, leave the header open.
+ // Otherwise, end it here.
+ if !w.needSniff {
+ io.WriteString(w.conn.buf, "\r\n")
+ }
+}
+
+// sniff uses the first block of written data,
+// stored in w.conn.body, to decide the Content-Type
+// for the HTTP body.
+func (w *response) sniff() {
+ if !w.needSniff {
+ return
+ }
+ w.needSniff = false
+
+ data := w.conn.body
+ fmt.Fprintf(w.conn.buf, "Content-Type: %s\r\n\r\n", DetectContentType(data))
+
+ if len(data) == 0 {
+ return
+ }
+ if w.chunking {
+ fmt.Fprintf(w.conn.buf, "%x\r\n", len(data))
+ }
+ _, err := w.conn.buf.Write(data)
+ if w.chunking && err == nil {
+ io.WriteString(w.conn.buf, "\r\n")
+ }
+}
+
+// bodyAllowed returns true if a Write is allowed for this response type.
+// It's illegal to call this before the header has been flushed.
+func (w *response) bodyAllowed() bool {
+ if !w.wroteHeader {
+ panic("")
+ }
+ return w.status != StatusNotModified && w.req.Method != "HEAD"
}
func (w *response) Write(data []byte) (n int, err os.Error) {
@@ -324,9 +418,7 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
if len(data) == 0 {
return 0, nil
}
-
- if w.status == StatusNotModified || w.req.Method == "HEAD" {
- // Must not have body.
+ if !w.bodyAllowed() {
return 0, ErrBodyNotAllowed
}
@@ -335,6 +427,32 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
return 0, ErrContentLength
}
+ var m int
+ if w.needSniff {
+ // We need to sniff the beginning of the output to
+ // determine the content type. Accumulate the
+ // initial writes in w.conn.body.
+ // Cap m so that append won't allocate.
+ m := cap(w.conn.body) - len(w.conn.body)
+ if m > len(data) {
+ m = len(data)
+ }
+ w.conn.body = append(w.conn.body, data[:m]...)
+ data = data[m:]
+ if len(data) == 0 {
+ // Copied everything into the buffer.
+ // Wait for next write.
+ return m, nil
+ }
+
+ // Filled the buffer; more data remains.
+ // Sniff the content (flushes the buffer)
+ // and then proceed with the remainder
+ // of the data as a normal Write.
+ // Calling sniff clears needSniff.
+ w.sniff()
+ }
+
// 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.
@@ -351,7 +469,7 @@ func (w *response) Write(data []byte) (n int, err os.Error) {
}
}
- return n, err
+ return m + n, err
}
// If this is an error reply (4xx or 5xx)
@@ -376,7 +494,7 @@ func errorKludge(w *response) {
// Is it a broken browser?
var msg string
- switch agent := w.req.UserAgent; {
+ switch agent := w.req.UserAgent(); {
case strings.Contains(agent, "MSIE"):
msg = "Internet Explorer"
case strings.Contains(agent, "Chrome/"):
@@ -387,7 +505,7 @@ func errorKludge(w *response) {
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.Get("Content-Type"), ";", 2)[0]
+ baseType := strings.SplitN(w.header.Get("Content-Type"), ";", 2)[0]
switch baseType {
case "text/html":
io.WriteString(w, "<!-- ")
@@ -415,6 +533,9 @@ func (w *response) finishRequest() {
if !w.wroteHeader {
w.WriteHeader(StatusOK)
}
+ if w.needSniff {
+ w.sniff()
+ }
errorKludge(w)
if w.chunking {
io.WriteString(w.conn.buf, "0\r\n")
@@ -437,6 +558,7 @@ func (w *response) Flush() {
if !w.wroteHeader {
w.WriteHeader(StatusOK)
}
+ w.sniff()
w.conn.buf.Flush()
}
@@ -454,9 +576,30 @@ func (c *conn) close() {
// Serve a new connection.
func (c *conn) serve() {
+ defer func() {
+ err := recover()
+ if err == nil {
+ return
+ }
+ c.rwc.Close()
+
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err)
+ buf.Write(debug.Stack())
+ log.Print(buf.String())
+ }()
+
for {
w, err := c.readRequest()
if err != nil {
+ if err == errTooLarge {
+ // Their HTTP client may or may not be
+ // able to read this if we're
+ // responding to them and hanging up
+ // while they're still writing their
+ // request. Undefined behavior.
+ fmt.Fprintf(c.rwc, "HTTP/1.1 400 Request Too Large\r\n\r\n")
+ }
break
}
@@ -470,6 +613,7 @@ func (c *conn) serve() {
if req.ContentLength == 0 {
w.Header().Set("Connection", "close")
w.WriteHeader(StatusBadRequest)
+ w.finishRequest()
break
}
req.Header.Del("Expect")
@@ -488,15 +632,21 @@ func (c *conn) serve() {
// respond with a 417 (Expectation Failed) status."
w.Header().Set("Connection", "close")
w.WriteHeader(StatusExpectationFailed)
+ w.finishRequest()
break
}
+ handler := c.server.Handler
+ if handler == nil {
+ handler = DefaultServeMux
+ }
+
// 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)
+ handler.ServeHTTP(w, w.req)
if c.hijacked {
return
}
@@ -528,7 +678,7 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err os.Error)
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Request)
-// ServeHTTP calls f(w, req).
+// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
@@ -549,10 +699,26 @@ func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", Sta
// that replies to each request with a ``404 page not found'' reply.
func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
+// StripPrefix returns a handler that serves HTTP requests
+// by removing the given prefix from the request URL's Path
+// and invoking the handler h. StripPrefix handles a
+// request for a path that doesn't begin with prefix by
+// replying with an HTTP 404 not found error.
+func StripPrefix(prefix string, h Handler) Handler {
+ return HandlerFunc(func(w ResponseWriter, r *Request) {
+ if !strings.HasPrefix(r.URL.Path, prefix) {
+ NotFound(w, r)
+ return
+ }
+ r.URL.Path = r.URL.Path[len(prefix):]
+ h.ServeHTTP(w, r)
+ })
+}
+
// 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 {
+func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
+ if u, err := url.Parse(urlStr); err == nil {
// If url was relative, make absolute by
// combining with request path.
// The browser would probably do this for us,
@@ -575,29 +741,35 @@ func Redirect(w ResponseWriter, r *Request, url string, code int) {
}
if u.Scheme == "" {
// no leading http://server
- if url == "" || url[0] != '/' {
+ if urlStr == "" || urlStr[0] != '/' {
// make relative path absolute
olddir, _ := path.Split(oldpath)
- url = olddir + url
+ urlStr = olddir + urlStr
+ }
+
+ var query string
+ if i := strings.Index(urlStr, "?"); i != -1 {
+ urlStr, query = urlStr[:i], urlStr[i:]
}
// clean up but preserve trailing slash
- trailing := url[len(url)-1] == '/'
- url = path.Clean(url)
- if trailing && url[len(url)-1] != '/' {
- url += "/"
+ trailing := urlStr[len(urlStr)-1] == '/'
+ urlStr = path.Clean(urlStr)
+ if trailing && urlStr[len(urlStr)-1] != '/' {
+ urlStr += "/"
}
+ urlStr += query
}
}
- w.Header().Set("Location", url)
+ w.Header().Set("Location", urlStr)
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"
+ note := "<a href=\"" + htmlEscape(urlStr) + "\">" + statusText[code] + "</a>.\n"
fmt.Fprintln(w, note)
}
}
@@ -772,10 +944,11 @@ func Serve(l net.Listener, handler Handler) os.Error {
// A Server defines parameters for running an HTTP server.
type Server struct {
- Addr string // TCP address to listen on, ":http" if empty
- Handler Handler // handler to invoke, http.DefaultServeMux if nil
- ReadTimeout int64 // the net.Conn.SetReadTimeout value for new connections
- WriteTimeout int64 // the net.Conn.SetWriteTimeout value for new connections
+ Addr string // TCP address to listen on, ":http" if empty
+ Handler Handler // handler to invoke, http.DefaultServeMux if nil
+ ReadTimeout int64 // the net.Conn.SetReadTimeout value for new connections
+ WriteTimeout int64 // the net.Conn.SetWriteTimeout value for new connections
+ MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0
}
// ListenAndServe listens on the TCP network address srv.Addr and then
@@ -798,13 +971,13 @@ func (srv *Server) ListenAndServe() os.Error {
// then call srv.Handler to reply to them.
func (srv *Server) Serve(l net.Listener) os.Error {
defer l.Close()
- handler := srv.Handler
- if handler == nil {
- handler = DefaultServeMux
- }
for {
rw, e := l.Accept()
if e != nil {
+ if ne, ok := e.(net.Error); ok && ne.Temporary() {
+ log.Printf("http: Accept error: %v", e)
+ continue
+ }
return e
}
if srv.ReadTimeout != 0 {
@@ -813,7 +986,7 @@ func (srv *Server) Serve(l net.Listener) os.Error {
if srv.WriteTimeout != 0 {
rw.SetWriteTimeout(srv.WriteTimeout)
}
- c, err := newConn(rw, handler)
+ c, err := srv.newConn(rw)
if err != nil {
continue
}
@@ -856,7 +1029,9 @@ func ListenAndServe(addr string, handler Handler) os.Error {
// ListenAndServeTLS acts identically to ListenAndServe, except that it
// expects HTTPS connections. Additionally, files containing a certificate and
-// matching private key for the server must be provided.
+// matching private key for the server must be provided. If the certificate
+// is signed by a certificate authority, the certFile should be the concatenation
+// of the server's certificate followed by the CA's certificate.
//
// A trivial example server is:
//
@@ -881,6 +1056,24 @@ func ListenAndServe(addr string, handler Handler) os.Error {
//
// One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.
func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) os.Error {
+ server := &Server{Addr: addr, Handler: handler}
+ return server.ListenAndServeTLS(certFile, keyFile)
+}
+
+// ListenAndServeTLS listens on the TCP network address srv.Addr and
+// then calls Serve to handle requests on incoming TLS connections.
+//
+// Filenames containing a certificate and matching private key for
+// the server must be provided. If the certificate is signed by a
+// certificate authority, the certFile should be the concatenation
+// of the server's certificate followed by the CA's certificate.
+//
+// If srv.Addr is blank, ":https" is used.
+func (s *Server) ListenAndServeTLS(certFile, keyFile string) os.Error {
+ addr := s.Addr
+ if addr == "" {
+ addr = ":https"
+ }
config := &tls.Config{
Rand: rand.Reader,
Time: time.Seconds,
@@ -900,7 +1093,7 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han
}
tlsListener := tls.NewListener(conn, config)
- return Serve(tlsListener, handler)
+ return s.Serve(tlsListener)
}
// TimeoutHandler returns a Handler that runs h with the given time limit.
diff --git a/libgo/go/http/sniff.go b/libgo/go/http/sniff.go
new file mode 100644
index 00000000000..d6086875073
--- /dev/null
+++ b/libgo/go/http/sniff.go
@@ -0,0 +1,214 @@
+// 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 http
+
+import (
+ "bytes"
+ "encoding/binary"
+)
+
+// Content-type sniffing algorithm.
+// References in this file refer to this draft specification:
+// http://tools.ietf.org/html/draft-ietf-websec-mime-sniff-03
+
+// The algorithm prefers to use sniffLen bytes to make its decision.
+const sniffLen = 512
+
+// DetectContentType returns the sniffed Content-Type string
+// for the given data. This function always returns a valid MIME type.
+func DetectContentType(data []byte) string {
+ if len(data) > sniffLen {
+ data = data[:sniffLen]
+ }
+
+ // Index of the first non-whitespace byte in data.
+ firstNonWS := 0
+ for ; firstNonWS < len(data) && isWS(data[firstNonWS]); firstNonWS++ {
+ }
+
+ for _, sig := range sniffSignatures {
+ if ct := sig.match(data, firstNonWS); ct != "" {
+ return ct
+ }
+ }
+
+ return "application/octet-stream" // fallback
+}
+
+func isWS(b byte) bool {
+ return bytes.IndexByte([]byte("\t\n\x0C\n "), b) != -1
+}
+
+type sniffSig interface {
+ // match returns the MIME type of the data, or "" if unknown.
+ match(data []byte, firstNonWS int) string
+}
+
+// Data matching the table in section 6.
+var sniffSignatures = []sniffSig{
+ htmlSig([]byte("<!DOCTYPE HTML")),
+ htmlSig([]byte("<HTML")),
+ htmlSig([]byte("<HEAD")),
+ htmlSig([]byte("<SCRIPT")),
+ htmlSig([]byte("<IFRAME")),
+ htmlSig([]byte("<H1")),
+ htmlSig([]byte("<DIV")),
+ htmlSig([]byte("<FONT")),
+ htmlSig([]byte("<TABLE")),
+ htmlSig([]byte("<A")),
+ htmlSig([]byte("<STYLE")),
+ htmlSig([]byte("<TITLE")),
+ htmlSig([]byte("<B")),
+ htmlSig([]byte("<BODY")),
+ htmlSig([]byte("<BR")),
+ htmlSig([]byte("<P")),
+ htmlSig([]byte("<!--")),
+
+ &maskedSig{mask: []byte("\xFF\xFF\xFF\xFF\xFF"), pat: []byte("<?xml"), skipWS: true, ct: "text/xml; charset=utf-8"},
+
+ &exactSig{[]byte("%PDF-"), "application/pdf"},
+ &exactSig{[]byte("%!PS-Adobe-"), "application/postscript"},
+
+ // UTF BOMs.
+ &maskedSig{mask: []byte("\xFF\xFF\x00\x00"), pat: []byte("\xFE\xFF\x00\x00"), ct: "text/plain; charset=utf-16be"},
+ &maskedSig{mask: []byte("\xFF\xFF\x00\x00"), pat: []byte("\xFF\xFE\x00\x00"), ct: "text/plain; charset=utf-16le"},
+ &maskedSig{mask: []byte("\xFF\xFF\xFF\x00"), pat: []byte("\xEF\xBB\xBF\x00"), ct: "text/plain; charset=utf-8"},
+
+ &exactSig{[]byte("GIF87a"), "image/gif"},
+ &exactSig{[]byte("GIF89a"), "image/gif"},
+ &exactSig{[]byte("\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"), "image/png"},
+ &exactSig{[]byte("\xFF\xD8\xFF"), "image/jpeg"},
+ &exactSig{[]byte("BM"), "image/bmp"},
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF"),
+ pat: []byte("RIFF\x00\x00\x00\x00WEBPVP"),
+ ct: "image/webp",
+ },
+ &exactSig{[]byte("\x00\x00\x01\x00"), "image/vnd.microsoft.icon"},
+ &exactSig{[]byte("\x4F\x67\x67\x53\x00"), "application/ogg"},
+ &maskedSig{
+ mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
+ pat: []byte("RIFF\x00\x00\x00\x00WAVE"),
+ ct: "audio/wave",
+ },
+ &exactSig{[]byte("\x1A\x45\xDF\xA3"), "video/webm"},
+ &exactSig{[]byte("\x52\x61\x72\x20\x1A\x07\x00"), "application/x-rar-compressed"},
+ &exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"},
+ &exactSig{[]byte("\x1F\x8B\x08"), "application/x-gzip"},
+
+ // TODO(dsymonds): Re-enable this when the spec is sorted w.r.t. MP4.
+ //mp4Sig(0),
+
+ textSig(0), // should be last
+}
+
+type exactSig struct {
+ sig []byte
+ ct string
+}
+
+func (e *exactSig) match(data []byte, firstNonWS int) string {
+ if bytes.HasPrefix(data, e.sig) {
+ return e.ct
+ }
+ return ""
+}
+
+type maskedSig struct {
+ mask, pat []byte
+ skipWS bool
+ ct string
+}
+
+func (m *maskedSig) match(data []byte, firstNonWS int) string {
+ if m.skipWS {
+ data = data[firstNonWS:]
+ }
+ if len(data) < len(m.mask) {
+ return ""
+ }
+ for i, mask := range m.mask {
+ db := data[i] & mask
+ if db != m.pat[i] {
+ return ""
+ }
+ }
+ return m.ct
+}
+
+type htmlSig []byte
+
+func (h htmlSig) match(data []byte, firstNonWS int) string {
+ data = data[firstNonWS:]
+ if len(data) < len(h)+1 {
+ return ""
+ }
+ for i, b := range h {
+ db := data[i]
+ if 'A' <= b && b <= 'Z' {
+ db &= 0xDF
+ }
+ if b != db {
+ return ""
+ }
+ }
+ // Next byte must be space or right angle bracket.
+ if db := data[len(h)]; db != ' ' && db != '>' {
+ return ""
+ }
+ return "text/html; charset=utf-8"
+}
+
+type mp4Sig int
+
+func (mp4Sig) match(data []byte, firstNonWS int) string {
+ // c.f. section 6.1.
+ if len(data) < 8 {
+ return ""
+ }
+ boxSize := int(binary.BigEndian.Uint32(data[:4]))
+ if boxSize%4 != 0 || len(data) < boxSize {
+ return ""
+ }
+ if !bytes.Equal(data[4:8], []byte("ftyp")) {
+ return ""
+ }
+ for st := 8; st < boxSize; st += 4 {
+ if st == 12 {
+ // minor version number
+ continue
+ }
+ seg := string(data[st : st+3])
+ switch seg {
+ case "mp4", "iso", "M4V", "M4P", "M4B":
+ return "video/mp4"
+ /* The remainder are not in the spec.
+ case "M4A":
+ return "audio/mp4"
+ case "3gp":
+ return "video/3gpp"
+ case "jp2":
+ return "image/jp2" // JPEG 2000
+ */
+ }
+ }
+ return ""
+}
+
+type textSig int
+
+func (textSig) match(data []byte, firstNonWS int) string {
+ // c.f. section 5, step 4.
+ for _, b := range data[firstNonWS:] {
+ switch {
+ case 0x00 <= b && b <= 0x08,
+ b == 0x0B,
+ 0x0E <= b && b <= 0x1A,
+ 0x1C <= b && b <= 0x1F:
+ return ""
+ }
+ }
+ return "text/plain; charset=utf-8"
+}
diff --git a/libgo/go/http/sniff_test.go b/libgo/go/http/sniff_test.go
new file mode 100644
index 00000000000..faf05e405a5
--- /dev/null
+++ b/libgo/go/http/sniff_test.go
@@ -0,0 +1,80 @@
+// 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 http_test
+
+import (
+ "bytes"
+ . "http"
+ "http/httptest"
+ "io/ioutil"
+ "log"
+ "strconv"
+ "testing"
+)
+
+var sniffTests = []struct {
+ desc string
+ data []byte
+ contentType string
+}{
+ // Some nonsense.
+ {"Empty", []byte{}, "text/plain; charset=utf-8"},
+ {"Binary", []byte{1, 2, 3}, "application/octet-stream"},
+
+ {"HTML document #1", []byte(`<HtMl><bOdY>blah blah blah</body></html>`), "text/html; charset=utf-8"},
+ {"HTML document #2", []byte(`<HTML></HTML>`), "text/html; charset=utf-8"},
+ {"HTML document #3 (leading whitespace)", []byte(` <!DOCTYPE HTML>...`), "text/html; charset=utf-8"},
+
+ {"Plain text", []byte(`This is not HTML. It has ☃ though.`), "text/plain; charset=utf-8"},
+
+ {"XML", []byte("\n<?xml!"), "text/xml; charset=utf-8"},
+
+ // Image types.
+ {"GIF 87a", []byte(`GIF87a`), "image/gif"},
+ {"GIF 89a", []byte(`GIF89a...`), "image/gif"},
+
+ // TODO(dsymonds): Re-enable this when the spec is sorted w.r.t. MP4.
+ //{"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
+ //{"MP4 audio", []byte("\x00\x00\x00\x20ftypM4A \x00\x00\x00\x00M4A mp42isom\x00\x00\x00\x00"), "audio/mp4"},
+}
+
+func TestDetectContentType(t *testing.T) {
+ for _, tt := range sniffTests {
+ ct := DetectContentType(tt.data)
+ if ct != tt.contentType {
+ t.Errorf("%v: DetectContentType = %q, want %q", tt.desc, ct, tt.contentType)
+ }
+ }
+}
+
+func TestServerContentType(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ i, _ := strconv.Atoi(r.FormValue("i"))
+ tt := sniffTests[i]
+ n, err := w.Write(tt.data)
+ if n != len(tt.data) || err != nil {
+ log.Fatalf("%v: Write(%q) = %v, %v want %d, nil", tt.desc, tt.data, n, err, len(tt.data))
+ }
+ }))
+ defer ts.Close()
+
+ for i, tt := range sniffTests {
+ resp, err := Get(ts.URL + "/?i=" + strconv.Itoa(i))
+ if err != nil {
+ t.Errorf("%v: %v", tt.desc, err)
+ continue
+ }
+ if ct := resp.Header.Get("Content-Type"); ct != tt.contentType {
+ t.Errorf("%v: Content-Type = %q, want %q", tt.desc, ct, tt.contentType)
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Errorf("%v: reading body: %v", tt.desc, err)
+ } else if !bytes.Equal(data, tt.data) {
+ t.Errorf("%v: data is %q, want %q", tt.desc, data, tt.data)
+ }
+ resp.Body.Close()
+ }
+}
diff --git a/libgo/go/http/spdy/protocol.go b/libgo/go/http/spdy/protocol.go
deleted file mode 100644
index d584ea232ea..00000000000
--- a/libgo/go/http/spdy/protocol.go
+++ /dev/null
@@ -1,367 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package spdy is an incomplete implementation of the SPDY protocol.
-//
-// The implementation follows draft 2 of the spec:
-// https://sites.google.com/a/chromium.org/dev/spdy/spdy-protocol/spdy-protocol-draft2
-package spdy
-
-import (
- "bytes"
- "compress/zlib"
- "encoding/binary"
- "http"
- "io"
- "os"
- "strconv"
- "strings"
- "sync"
-)
-
-// Version is the protocol version number that this package implements.
-const Version = 2
-
-// ControlFrameType stores the type field in a control frame header.
-type ControlFrameType uint16
-
-// Control frame type constants
-const (
- TypeSynStream ControlFrameType = 0x0001
- TypeSynReply = 0x0002
- TypeRstStream = 0x0003
- TypeSettings = 0x0004
- TypeNoop = 0x0005
- TypePing = 0x0006
- TypeGoaway = 0x0007
- TypeHeaders = 0x0008
- TypeWindowUpdate = 0x0009
-)
-
-func (t ControlFrameType) String() string {
- switch t {
- case TypeSynStream:
- return "SYN_STREAM"
- case TypeSynReply:
- return "SYN_REPLY"
- case TypeRstStream:
- return "RST_STREAM"
- case TypeSettings:
- return "SETTINGS"
- case TypeNoop:
- return "NOOP"
- case TypePing:
- return "PING"
- case TypeGoaway:
- return "GOAWAY"
- case TypeHeaders:
- return "HEADERS"
- case TypeWindowUpdate:
- return "WINDOW_UPDATE"
- }
- return "Type(" + strconv.Itoa(int(t)) + ")"
-}
-
-type FrameFlags uint8
-
-// Stream frame flags
-const (
- FlagFin FrameFlags = 0x01
- FlagUnidirectional = 0x02
-)
-
-// SETTINGS frame flags
-const (
- FlagClearPreviouslyPersistedSettings FrameFlags = 0x01
-)
-
-// MaxDataLength is the maximum number of bytes that can be stored in one frame.
-const MaxDataLength = 1<<24 - 1
-
-// A Frame is a framed message as sent between clients and servers.
-// There are two types of frames: control frames and data frames.
-type Frame struct {
- Header [4]byte
- Flags FrameFlags
- Data []byte
-}
-
-// ControlFrame creates a control frame with the given information.
-func ControlFrame(t ControlFrameType, f FrameFlags, data []byte) Frame {
- return Frame{
- Header: [4]byte{
- (Version&0xff00)>>8 | 0x80,
- (Version & 0x00ff),
- byte((t & 0xff00) >> 8),
- byte((t & 0x00ff) >> 0),
- },
- Flags: f,
- Data: data,
- }
-}
-
-// DataFrame creates a data frame with the given information.
-func DataFrame(streamId uint32, f FrameFlags, data []byte) Frame {
- return Frame{
- Header: [4]byte{
- byte(streamId & 0x7f000000 >> 24),
- byte(streamId & 0x00ff0000 >> 16),
- byte(streamId & 0x0000ff00 >> 8),
- byte(streamId & 0x000000ff >> 0),
- },
- Flags: f,
- Data: data,
- }
-}
-
-// ReadFrame reads an entire frame into memory.
-func ReadFrame(r io.Reader) (f Frame, err os.Error) {
- _, err = io.ReadFull(r, f.Header[:])
- if err != nil {
- return
- }
- err = binary.Read(r, binary.BigEndian, &f.Flags)
- if err != nil {
- return
- }
- var lengthField [3]byte
- _, err = io.ReadFull(r, lengthField[:])
- if err != nil {
- if err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
- return
- }
- var length uint32
- length |= uint32(lengthField[0]) << 16
- length |= uint32(lengthField[1]) << 8
- length |= uint32(lengthField[2]) << 0
- if length > 0 {
- f.Data = make([]byte, int(length))
- _, err = io.ReadFull(r, f.Data)
- if err == os.EOF {
- err = io.ErrUnexpectedEOF
- }
- } else {
- f.Data = []byte{}
- }
- return
-}
-
-// IsControl returns whether the frame holds a control frame.
-func (f Frame) IsControl() bool {
- return f.Header[0]&0x80 != 0
-}
-
-// Type obtains the type field if the frame is a control frame, otherwise it returns zero.
-func (f Frame) Type() ControlFrameType {
- if !f.IsControl() {
- return 0
- }
- return (ControlFrameType(f.Header[2])<<8 | ControlFrameType(f.Header[3]))
-}
-
-// StreamId returns the stream ID field if the frame is a data frame, otherwise it returns zero.
-func (f Frame) StreamId() (id uint32) {
- if f.IsControl() {
- return 0
- }
- id |= uint32(f.Header[0]) << 24
- id |= uint32(f.Header[1]) << 16
- id |= uint32(f.Header[2]) << 8
- id |= uint32(f.Header[3]) << 0
- return
-}
-
-// WriteTo writes the frame in the SPDY format.
-func (f Frame) WriteTo(w io.Writer) (n int64, err os.Error) {
- var nn int
- // Header
- nn, err = w.Write(f.Header[:])
- n += int64(nn)
- if err != nil {
- return
- }
- // Flags
- nn, err = w.Write([]byte{byte(f.Flags)})
- n += int64(nn)
- if err != nil {
- return
- }
- // Length
- nn, err = w.Write([]byte{
- byte(len(f.Data) & 0x00ff0000 >> 16),
- byte(len(f.Data) & 0x0000ff00 >> 8),
- byte(len(f.Data) & 0x000000ff),
- })
- n += int64(nn)
- if err != nil {
- return
- }
- // Data
- if len(f.Data) > 0 {
- nn, err = w.Write(f.Data)
- n += int64(nn)
- }
- return
-}
-
-// headerDictionary is the dictionary sent to the zlib compressor/decompressor.
-// Even though the specification states there is no null byte at the end, Chrome sends it.
-const headerDictionary = "optionsgetheadpostputdeletetrace" +
- "acceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhost" +
- "if-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsince" +
- "max-forwardsproxy-authorizationrangerefererteuser-agent" +
- "100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505" +
- "accept-rangesageetaglocationproxy-authenticatepublicretry-after" +
- "servervarywarningwww-authenticateallowcontent-basecontent-encodingcache-control" +
- "connectiondatetrailertransfer-encodingupgradeviawarning" +
- "content-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookie" +
- "MondayTuesdayWednesdayThursdayFridaySaturdaySunday" +
- "JanFebMarAprMayJunJulAugSepOctNovDec" +
- "chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" +
- "charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00"
-
-// hrSource is a reader that passes through reads from another reader.
-// When the underlying reader reaches EOF, Read will block until another reader is added via change.
-type hrSource struct {
- r io.Reader
- m sync.RWMutex
- c *sync.Cond
-}
-
-func (src *hrSource) Read(p []byte) (n int, err os.Error) {
- src.m.RLock()
- for src.r == nil {
- src.c.Wait()
- }
- n, err = src.r.Read(p)
- src.m.RUnlock()
- if err == os.EOF {
- src.change(nil)
- err = nil
- }
- return
-}
-
-func (src *hrSource) change(r io.Reader) {
- src.m.Lock()
- defer src.m.Unlock()
- src.r = r
- src.c.Broadcast()
-}
-
-// A HeaderReader reads zlib-compressed headers.
-type HeaderReader struct {
- source hrSource
- decompressor io.ReadCloser
-}
-
-// NewHeaderReader creates a HeaderReader with the initial dictionary.
-func NewHeaderReader() (hr *HeaderReader) {
- hr = new(HeaderReader)
- hr.source.c = sync.NewCond(hr.source.m.RLocker())
- return
-}
-
-// ReadHeader reads a set of headers from a reader.
-func (hr *HeaderReader) ReadHeader(r io.Reader) (h http.Header, err os.Error) {
- hr.source.change(r)
- h, err = hr.read()
- return
-}
-
-// Decode reads a set of headers from a block of bytes.
-func (hr *HeaderReader) Decode(data []byte) (h http.Header, err os.Error) {
- hr.source.change(bytes.NewBuffer(data))
- h, err = hr.read()
- return
-}
-
-func (hr *HeaderReader) read() (h http.Header, err os.Error) {
- var count uint16
- if hr.decompressor == nil {
- hr.decompressor, err = zlib.NewReaderDict(&hr.source, []byte(headerDictionary))
- if err != nil {
- return
- }
- }
- err = binary.Read(hr.decompressor, binary.BigEndian, &count)
- if err != nil {
- return
- }
- h = make(http.Header, int(count))
- for i := 0; i < int(count); i++ {
- var name, value string
- name, err = readHeaderString(hr.decompressor)
- if err != nil {
- return
- }
- value, err = readHeaderString(hr.decompressor)
- if err != nil {
- return
- }
- valueList := strings.Split(string(value), "\x00", -1)
- for _, v := range valueList {
- h.Add(name, v)
- }
- }
- return
-}
-
-func readHeaderString(r io.Reader) (s string, err os.Error) {
- var length uint16
- err = binary.Read(r, binary.BigEndian, &length)
- if err != nil {
- return
- }
- data := make([]byte, int(length))
- _, err = io.ReadFull(r, data)
- if err != nil {
- return
- }
- return string(data), nil
-}
-
-// HeaderWriter will write zlib-compressed headers on different streams.
-type HeaderWriter struct {
- compressor *zlib.Writer
- buffer *bytes.Buffer
-}
-
-// NewHeaderWriter creates a HeaderWriter ready to compress headers.
-func NewHeaderWriter(level int) (hw *HeaderWriter) {
- hw = &HeaderWriter{buffer: new(bytes.Buffer)}
- hw.compressor, _ = zlib.NewWriterDict(hw.buffer, level, []byte(headerDictionary))
- return
-}
-
-// WriteHeader writes a header block directly to an output.
-func (hw *HeaderWriter) WriteHeader(w io.Writer, h http.Header) (err os.Error) {
- hw.write(h)
- _, err = io.Copy(w, hw.buffer)
- hw.buffer.Reset()
- return
-}
-
-// Encode returns a compressed header block.
-func (hw *HeaderWriter) Encode(h http.Header) (data []byte) {
- hw.write(h)
- data = make([]byte, hw.buffer.Len())
- hw.buffer.Read(data)
- return
-}
-
-func (hw *HeaderWriter) write(h http.Header) {
- binary.Write(hw.compressor, binary.BigEndian, uint16(len(h)))
- for k, vals := range h {
- k = strings.ToLower(k)
- binary.Write(hw.compressor, binary.BigEndian, uint16(len(k)))
- binary.Write(hw.compressor, binary.BigEndian, []byte(k))
- v := strings.Join(vals, "\x00")
- binary.Write(hw.compressor, binary.BigEndian, uint16(len(v)))
- binary.Write(hw.compressor, binary.BigEndian, []byte(v))
- }
- hw.compressor.Flush()
-}
diff --git a/libgo/go/http/spdy/protocol_test.go b/libgo/go/http/spdy/protocol_test.go
deleted file mode 100644
index 998ff998bc7..00000000000
--- a/libgo/go/http/spdy/protocol_test.go
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package spdy
-
-import (
- "bytes"
- "compress/zlib"
- "http"
- "os"
- "testing"
-)
-
-type frameIoTest struct {
- desc string
- data []byte
- frame Frame
- readError os.Error
- readOnly bool
-}
-
-var frameIoTests = []frameIoTest{
- {
- "noop frame",
- []byte{
- 0x80, 0x02, 0x00, 0x05,
- 0x00, 0x00, 0x00, 0x00,
- },
- ControlFrame(
- TypeNoop,
- 0x00,
- []byte{},
- ),
- nil,
- false,
- },
- {
- "ping frame",
- []byte{
- 0x80, 0x02, 0x00, 0x06,
- 0x00, 0x00, 0x00, 0x04,
- 0x00, 0x00, 0x00, 0x01,
- },
- ControlFrame(
- TypePing,
- 0x00,
- []byte{0x00, 0x00, 0x00, 0x01},
- ),
- nil,
- false,
- },
- {
- "syn_stream frame",
- []byte{
- 0x80, 0x02, 0x00, 0x01,
- 0x01, 0x00, 0x00, 0x53,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x78, 0xbb,
- 0xdf, 0xa2, 0x51, 0xb2,
- 0x62, 0x60, 0x66, 0x60,
- 0xcb, 0x4d, 0x2d, 0xc9,
- 0xc8, 0x4f, 0x61, 0x60,
- 0x4e, 0x4f, 0x2d, 0x61,
- 0x60, 0x2e, 0x2d, 0xca,
- 0x61, 0x10, 0xcb, 0x28,
- 0x29, 0x29, 0xb0, 0xd2,
- 0xd7, 0x2f, 0x2f, 0x2f,
- 0xd7, 0x4b, 0xcf, 0xcf,
- 0x4f, 0xcf, 0x49, 0xd5,
- 0x4b, 0xce, 0xcf, 0xd5,
- 0x67, 0x60, 0x2f, 0x4b,
- 0x2d, 0x2a, 0xce, 0xcc,
- 0xcf, 0x63, 0xe0, 0x00,
- 0x29, 0xd0, 0x37, 0xd4,
- 0x33, 0x04, 0x00, 0x00,
- 0x00, 0xff, 0xff,
- },
- ControlFrame(
- TypeSynStream,
- 0x01,
- []byte{
- 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x78, 0xbb,
- 0xdf, 0xa2, 0x51, 0xb2,
- 0x62, 0x60, 0x66, 0x60,
- 0xcb, 0x4d, 0x2d, 0xc9,
- 0xc8, 0x4f, 0x61, 0x60,
- 0x4e, 0x4f, 0x2d, 0x61,
- 0x60, 0x2e, 0x2d, 0xca,
- 0x61, 0x10, 0xcb, 0x28,
- 0x29, 0x29, 0xb0, 0xd2,
- 0xd7, 0x2f, 0x2f, 0x2f,
- 0xd7, 0x4b, 0xcf, 0xcf,
- 0x4f, 0xcf, 0x49, 0xd5,
- 0x4b, 0xce, 0xcf, 0xd5,
- 0x67, 0x60, 0x2f, 0x4b,
- 0x2d, 0x2a, 0xce, 0xcc,
- 0xcf, 0x63, 0xe0, 0x00,
- 0x29, 0xd0, 0x37, 0xd4,
- 0x33, 0x04, 0x00, 0x00,
- 0x00, 0xff, 0xff,
- },
- ),
- nil,
- false,
- },
- {
- "data frame",
- []byte{
- 0x00, 0x00, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x04,
- 0x01, 0x02, 0x03, 0x04,
- },
- DataFrame(
- 5,
- 0x01,
- []byte{0x01, 0x02, 0x03, 0x04},
- ),
- nil,
- false,
- },
- {
- "too much data",
- []byte{
- 0x00, 0x00, 0x00, 0x05,
- 0x01, 0x00, 0x00, 0x04,
- 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08,
- },
- DataFrame(
- 5,
- 0x01,
- []byte{0x01, 0x02, 0x03, 0x04},
- ),
- nil,
- true,
- },
- {
- "not enough data",
- []byte{
- 0x00, 0x00, 0x00, 0x05,
- },
- Frame{},
- os.EOF,
- true,
- },
-}
-
-func TestReadFrame(t *testing.T) {
- for _, tt := range frameIoTests {
- f, err := ReadFrame(bytes.NewBuffer(tt.data))
- if err != tt.readError {
- t.Errorf("%s: ReadFrame: %s", tt.desc, err)
- continue
- }
- if err == nil {
- if !bytes.Equal(f.Header[:], tt.frame.Header[:]) {
- t.Errorf("%s: header %q != %q", tt.desc, string(f.Header[:]), string(tt.frame.Header[:]))
- }
- if f.Flags != tt.frame.Flags {
- t.Errorf("%s: flags %#02x != %#02x", tt.desc, f.Flags, tt.frame.Flags)
- }
- if !bytes.Equal(f.Data, tt.frame.Data) {
- t.Errorf("%s: data %q != %q", tt.desc, string(f.Data), string(tt.frame.Data))
- }
- }
- }
-}
-
-func TestWriteTo(t *testing.T) {
- for _, tt := range frameIoTests {
- if tt.readOnly {
- continue
- }
- b := new(bytes.Buffer)
- _, err := tt.frame.WriteTo(b)
- if err != nil {
- t.Errorf("%s: WriteTo: %s", tt.desc, err)
- }
- if !bytes.Equal(b.Bytes(), tt.data) {
- t.Errorf("%s: data %q != %q", tt.desc, string(b.Bytes()), string(tt.data))
- }
- }
-}
-
-var headerDataTest = []byte{
- 0x78, 0xbb, 0xdf, 0xa2,
- 0x51, 0xb2, 0x62, 0x60,
- 0x66, 0x60, 0xcb, 0x4d,
- 0x2d, 0xc9, 0xc8, 0x4f,
- 0x61, 0x60, 0x4e, 0x4f,
- 0x2d, 0x61, 0x60, 0x2e,
- 0x2d, 0xca, 0x61, 0x10,
- 0xcb, 0x28, 0x29, 0x29,
- 0xb0, 0xd2, 0xd7, 0x2f,
- 0x2f, 0x2f, 0xd7, 0x4b,
- 0xcf, 0xcf, 0x4f, 0xcf,
- 0x49, 0xd5, 0x4b, 0xce,
- 0xcf, 0xd5, 0x67, 0x60,
- 0x2f, 0x4b, 0x2d, 0x2a,
- 0xce, 0xcc, 0xcf, 0x63,
- 0xe0, 0x00, 0x29, 0xd0,
- 0x37, 0xd4, 0x33, 0x04,
- 0x00, 0x00, 0x00, 0xff,
- 0xff,
-}
-
-func TestReadHeader(t *testing.T) {
- r := NewHeaderReader()
- h, err := r.Decode(headerDataTest)
- if err != nil {
- t.Fatalf("Error: %v", err)
- return
- }
- if len(h) != 3 {
- t.Errorf("Header count = %d (expected 3)", len(h))
- }
- if h.Get("Url") != "http://www.google.com/" {
- t.Errorf("Url: %q != %q", h.Get("Url"), "http://www.google.com/")
- }
- if h.Get("Method") != "get" {
- t.Errorf("Method: %q != %q", h.Get("Method"), "get")
- }
- if h.Get("Version") != "http/1.1" {
- t.Errorf("Version: %q != %q", h.Get("Version"), "http/1.1")
- }
-}
-
-func TestWriteHeader(t *testing.T) {
- for level := zlib.NoCompression; level <= zlib.BestCompression; level++ {
- r := NewHeaderReader()
- w := NewHeaderWriter(level)
- for i := 0; i < 100; i++ {
- b := new(bytes.Buffer)
- gold := http.Header{
- "Url": []string{"http://www.google.com/"},
- "Method": []string{"get"},
- "Version": []string{"http/1.1"},
- }
- w.WriteHeader(b, gold)
- h, err := r.Decode(b.Bytes())
- if err != nil {
- t.Errorf("(level=%d i=%d) Error: %v", level, i, err)
- return
- }
- if len(h) != len(gold) {
- t.Errorf("(level=%d i=%d) Header count = %d (expected %d)", level, i, len(h), len(gold))
- }
- for k, _ := range h {
- if h.Get(k) != gold.Get(k) {
- t.Errorf("(level=%d i=%d) %s: %q != %q", level, i, k, h.Get(k), gold.Get(k))
- }
- }
- }
- }
-}
diff --git a/libgo/go/http/spdy/read.go b/libgo/go/http/spdy/read.go
new file mode 100644
index 00000000000..c6b6ab3af84
--- /dev/null
+++ b/libgo/go/http/spdy/read.go
@@ -0,0 +1,313 @@
+// 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 spdy
+
+import (
+ "compress/zlib"
+ "encoding/binary"
+ "http"
+ "io"
+ "os"
+ "strings"
+)
+
+func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ return f.readSynStreamFrame(h, frame)
+}
+
+func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ return f.readSynReplyFrame(h, frame)
+}
+
+func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
+ return err
+ }
+ if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ var numSettings uint32
+ if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil {
+ return err
+ }
+ frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings)
+ for i := uint32(0); i < numSettings; i++ {
+ if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil {
+ return err
+ }
+ frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24)
+ frame.FlagIdValues[i].Id &= 0xffffff
+ if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (frame *NoopFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ return nil
+}
+
+func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ frame.CFHeader = h
+ if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) os.Error {
+ return f.readHeadersFrame(h, frame)
+}
+
+func newControlFrame(frameType ControlFrameType) (controlFrame, os.Error) {
+ ctor, ok := cframeCtor[frameType]
+ if !ok {
+ return nil, &Error{Err: InvalidControlFrame}
+ }
+ return ctor(), nil
+}
+
+var cframeCtor = map[ControlFrameType]func() controlFrame{
+ TypeSynStream: func() controlFrame { return new(SynStreamFrame) },
+ TypeSynReply: func() controlFrame { return new(SynReplyFrame) },
+ TypeRstStream: func() controlFrame { return new(RstStreamFrame) },
+ TypeSettings: func() controlFrame { return new(SettingsFrame) },
+ TypeNoop: func() controlFrame { return new(NoopFrame) },
+ TypePing: func() controlFrame { return new(PingFrame) },
+ TypeGoAway: func() controlFrame { return new(GoAwayFrame) },
+ TypeHeaders: func() controlFrame { return new(HeadersFrame) },
+ // TODO(willchan): Add TypeWindowUpdate
+}
+
+func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) os.Error {
+ if f.headerDecompressor != nil {
+ f.headerReader.N = payloadSize
+ return nil
+ }
+ f.headerReader = io.LimitedReader{R: f.r, N: payloadSize}
+ decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(HeaderDictionary))
+ if err != nil {
+ return err
+ }
+ f.headerDecompressor = decompressor
+ return nil
+}
+
+// ReadFrame reads SPDY encoded data and returns a decompressed Frame.
+func (f *Framer) ReadFrame() (Frame, os.Error) {
+ var firstWord uint32
+ if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil {
+ return nil, err
+ }
+ if (firstWord & 0x80000000) != 0 {
+ frameType := ControlFrameType(firstWord & 0xffff)
+ version := uint16(0x7fff & (firstWord >> 16))
+ return f.parseControlFrame(version, frameType)
+ }
+ return f.parseDataFrame(firstWord & 0x7fffffff)
+}
+
+func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, os.Error) {
+ var length uint32
+ if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ flags := ControlFlags((length & 0xff000000) >> 24)
+ length &= 0xffffff
+ header := ControlFrameHeader{version, frameType, flags, length}
+ cframe, err := newControlFrame(frameType)
+ if err != nil {
+ return nil, err
+ }
+ if err = cframe.read(header, f); err != nil {
+ return nil, err
+ }
+ return cframe, nil
+}
+
+func parseHeaderValueBlock(r io.Reader, streamId uint32) (http.Header, os.Error) {
+ var numHeaders uint16
+ if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil {
+ return nil, err
+ }
+ var e os.Error
+ h := make(http.Header, int(numHeaders))
+ for i := 0; i < int(numHeaders); i++ {
+ var length uint16
+ if err := binary.Read(r, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ nameBytes := make([]byte, length)
+ if _, err := io.ReadFull(r, nameBytes); err != nil {
+ return nil, err
+ }
+ name := string(nameBytes)
+ if name != strings.ToLower(name) {
+ e = &Error{UnlowercasedHeaderName, streamId}
+ name = strings.ToLower(name)
+ }
+ if h[name] != nil {
+ e = &Error{DuplicateHeaders, streamId}
+ }
+ if err := binary.Read(r, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ value := make([]byte, length)
+ if _, err := io.ReadFull(r, value); err != nil {
+ return nil, err
+ }
+ valueList := strings.Split(string(value), "\x00")
+ for _, v := range valueList {
+ h.Add(name, v)
+ }
+ }
+ if e != nil {
+ return h, e
+ }
+ return h, nil
+}
+
+func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) os.Error {
+ frame.CFHeader = h
+ var err os.Error
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
+ return err
+ }
+ if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil {
+ return err
+ }
+ if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil {
+ return err
+ }
+ frame.Priority >>= 14
+
+ reader := f.r
+ if !f.headerCompressionDisabled {
+ f.uncorkHeaderDecompressor(int64(h.length - 10))
+ reader = f.headerDecompressor
+ }
+
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
+ if err != nil {
+ return err
+ }
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ for h, _ := range frame.Headers {
+ if invalidReqHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
+ return nil
+}
+
+func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) os.Error {
+ frame.CFHeader = h
+ var err os.Error
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
+ return err
+ }
+ var unused uint16
+ if err = binary.Read(f.r, binary.BigEndian, &unused); err != nil {
+ return err
+ }
+ reader := f.r
+ if !f.headerCompressionDisabled {
+ f.uncorkHeaderDecompressor(int64(h.length - 6))
+ reader = f.headerDecompressor
+ }
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
+ if err != nil {
+ return err
+ }
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ for h, _ := range frame.Headers {
+ if invalidRespHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
+ return nil
+}
+
+func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) os.Error {
+ frame.CFHeader = h
+ var err os.Error
+ if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
+ return err
+ }
+ var unused uint16
+ if err = binary.Read(f.r, binary.BigEndian, &unused); err != nil {
+ return err
+ }
+ reader := f.r
+ if !f.headerCompressionDisabled {
+ f.uncorkHeaderDecompressor(int64(h.length - 6))
+ reader = f.headerDecompressor
+ }
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
+ if err != nil {
+ return err
+ }
+
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ var invalidHeaders map[string]bool
+ if frame.StreamId%2 == 0 {
+ invalidHeaders = invalidReqHeaders
+ } else {
+ invalidHeaders = invalidRespHeaders
+ }
+ for h, _ := range frame.Headers {
+ if invalidHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
+ return nil
+}
+
+func (f *Framer) parseDataFrame(streamId uint32) (*DataFrame, os.Error) {
+ var length uint32
+ if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
+ return nil, err
+ }
+ var frame DataFrame
+ frame.StreamId = streamId
+ frame.Flags = DataFlags(length >> 24)
+ length &= 0xffffff
+ frame.Data = make([]byte, length)
+ if _, err := io.ReadFull(f.r, frame.Data); err != nil {
+ return nil, err
+ }
+ return &frame, nil
+}
diff --git a/libgo/go/http/spdy/spdy_test.go b/libgo/go/http/spdy/spdy_test.go
new file mode 100644
index 00000000000..cb91e028613
--- /dev/null
+++ b/libgo/go/http/spdy/spdy_test.go
@@ -0,0 +1,497 @@
+// 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 spdy
+
+import (
+ "bytes"
+ "http"
+ "io"
+ "reflect"
+ "testing"
+)
+
+func TestHeaderParsing(t *testing.T) {
+ headers := http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ }
+ var headerValueBlockBuf bytes.Buffer
+ writeHeaderValueBlock(&headerValueBlockBuf, headers)
+
+ const bogusStreamId = 1
+ newHeaders, err := parseHeaderValueBlock(&headerValueBlockBuf, bogusStreamId)
+ if err != nil {
+ t.Fatal("parseHeaderValueBlock:", err)
+ }
+
+ if !reflect.DeepEqual(headers, newHeaders) {
+ t.Fatal("got: ", newHeaders, "\nwant: ", headers)
+ }
+}
+
+func TestCreateParseSynStreamFrame(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer := &Framer{
+ headerCompressionDisabled: true,
+ w: buffer,
+ headerBuf: new(bytes.Buffer),
+ r: buffer,
+ }
+ synStreamFrame := SynStreamFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeSynStream,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
+ t.Fatal("WriteFrame without compression:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame without compression:", err)
+ }
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
+ }
+
+ // Test again with compression
+ buffer.Reset()
+ framer, err = NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
+ t.Fatal("WriteFrame with compression:", err)
+ }
+ frame, err = framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame with compression:", err)
+ }
+ parsedSynStreamFrame, ok = frame.(*SynStreamFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
+ }
+}
+
+func TestCreateParseSynReplyFrame(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer := &Framer{
+ headerCompressionDisabled: true,
+ w: buffer,
+ headerBuf: new(bytes.Buffer),
+ r: buffer,
+ }
+ synReplyFrame := SynReplyFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeSynReply,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+ if err := framer.WriteFrame(&synReplyFrame); err != nil {
+ t.Fatal("WriteFrame without compression:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame without compression:", err)
+ }
+ parsedSynReplyFrame, ok := frame.(*SynReplyFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) {
+ t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame)
+ }
+
+ // Test again with compression
+ buffer.Reset()
+ framer, err = NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ if err := framer.WriteFrame(&synReplyFrame); err != nil {
+ t.Fatal("WriteFrame with compression:", err)
+ }
+ frame, err = framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame with compression:", err)
+ }
+ parsedSynReplyFrame, ok = frame.(*SynReplyFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(synReplyFrame, *parsedSynReplyFrame) {
+ t.Fatal("got: ", *parsedSynReplyFrame, "\nwant: ", synReplyFrame)
+ }
+}
+
+func TestCreateParseRstStream(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ rstStreamFrame := RstStreamFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeRstStream,
+ },
+ StreamId: 1,
+ Status: InvalidStream,
+ }
+ if err := framer.WriteFrame(&rstStreamFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedRstStreamFrame, ok := frame.(*RstStreamFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(rstStreamFrame, *parsedRstStreamFrame) {
+ t.Fatal("got: ", *parsedRstStreamFrame, "\nwant: ", rstStreamFrame)
+ }
+}
+
+func TestCreateParseSettings(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ settingsFrame := SettingsFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeSettings,
+ },
+ FlagIdValues: []SettingsFlagIdValue{
+ {FlagSettingsPersistValue, SettingsCurrentCwnd, 10},
+ {FlagSettingsPersisted, SettingsUploadBandwidth, 1},
+ },
+ }
+ if err := framer.WriteFrame(&settingsFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedSettingsFrame, ok := frame.(*SettingsFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(settingsFrame, *parsedSettingsFrame) {
+ t.Fatal("got: ", *parsedSettingsFrame, "\nwant: ", settingsFrame)
+ }
+}
+
+func TestCreateParseNoop(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ noopFrame := NoopFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeNoop,
+ },
+ }
+ if err := framer.WriteFrame(&noopFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedNoopFrame, ok := frame.(*NoopFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(noopFrame, *parsedNoopFrame) {
+ t.Fatal("got: ", *parsedNoopFrame, "\nwant: ", noopFrame)
+ }
+}
+
+func TestCreateParsePing(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ pingFrame := PingFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypePing,
+ },
+ Id: 31337,
+ }
+ if err := framer.WriteFrame(&pingFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedPingFrame, ok := frame.(*PingFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(pingFrame, *parsedPingFrame) {
+ t.Fatal("got: ", *parsedPingFrame, "\nwant: ", pingFrame)
+ }
+}
+
+func TestCreateParseGoAway(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ goAwayFrame := GoAwayFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeGoAway,
+ },
+ LastGoodStreamId: 31337,
+ }
+ if err := framer.WriteFrame(&goAwayFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedGoAwayFrame, ok := frame.(*GoAwayFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(goAwayFrame, *parsedGoAwayFrame) {
+ t.Fatal("got: ", *parsedGoAwayFrame, "\nwant: ", goAwayFrame)
+ }
+}
+
+func TestCreateParseHeadersFrame(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer := &Framer{
+ headerCompressionDisabled: true,
+ w: buffer,
+ headerBuf: new(bytes.Buffer),
+ r: buffer,
+ }
+ headersFrame := HeadersFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeHeaders,
+ },
+ }
+ headersFrame.Headers = http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ }
+ if err := framer.WriteFrame(&headersFrame); err != nil {
+ t.Fatal("WriteFrame without compression:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame without compression:", err)
+ }
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
+ }
+
+ // Test again with compression
+ buffer.Reset()
+ framer, err = NewFramer(buffer, buffer)
+ if err := framer.WriteFrame(&headersFrame); err != nil {
+ t.Fatal("WriteFrame with compression:", err)
+ }
+ frame, err = framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame with compression:", err)
+ }
+ parsedHeadersFrame, ok = frame.(*HeadersFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
+ }
+}
+
+func TestCreateParseDataFrame(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ dataFrame := DataFrame{
+ StreamId: 1,
+ Data: []byte{'h', 'e', 'l', 'l', 'o'},
+ }
+ if err := framer.WriteFrame(&dataFrame); err != nil {
+ t.Fatal("WriteFrame:", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame:", err)
+ }
+ parsedDataFrame, ok := frame.(*DataFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(dataFrame, *parsedDataFrame) {
+ t.Fatal("got: ", *parsedDataFrame, "\nwant: ", dataFrame)
+ }
+}
+
+func TestCompressionContextAcrossFrames(t *testing.T) {
+ buffer := new(bytes.Buffer)
+ framer, err := NewFramer(buffer, buffer)
+ if err != nil {
+ t.Fatal("Failed to create new framer:", err)
+ }
+ headersFrame := HeadersFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeHeaders,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+ if err := framer.WriteFrame(&headersFrame); err != nil {
+ t.Fatal("WriteFrame (HEADERS):", err)
+ }
+ synStreamFrame := SynStreamFrame{ControlFrameHeader{Version, TypeSynStream, 0, 0}, 0, 0, 0, nil}
+ synStreamFrame.Headers = http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ }
+ if err := framer.WriteFrame(&synStreamFrame); err != nil {
+ t.Fatal("WriteFrame (SYN_STREAM):", err)
+ }
+ frame, err := framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame (HEADERS):", err, buffer.Bytes())
+ }
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
+ if !ok {
+ t.Fatalf("expected HeadersFrame; got %T %v", frame, frame)
+ }
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
+ }
+ frame, err = framer.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame (SYN_STREAM):", err, buffer.Bytes())
+ }
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
+ if !ok {
+ t.Fatalf("expected SynStreamFrame; got %T %v", frame, frame)
+ }
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
+ }
+}
+
+func TestMultipleSPDYFrames(t *testing.T) {
+ // Initialize the framers.
+ pr1, pw1 := io.Pipe()
+ pr2, pw2 := io.Pipe()
+ writer, err := NewFramer(pw1, pr2)
+ if err != nil {
+ t.Fatal("Failed to create writer:", err)
+ }
+ reader, err := NewFramer(pw2, pr1)
+ if err != nil {
+ t.Fatal("Failed to create reader:", err)
+ }
+
+ // Set up the frames we're actually transferring.
+ headersFrame := HeadersFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeHeaders,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+ synStreamFrame := SynStreamFrame{
+ CFHeader: ControlFrameHeader{
+ version: Version,
+ frameType: TypeSynStream,
+ },
+ Headers: http.Header{
+ "Url": []string{"http://www.google.com/"},
+ "Method": []string{"get"},
+ "Version": []string{"http/1.1"},
+ },
+ }
+
+ // Start the goroutines to write the frames.
+ go func() {
+ if err := writer.WriteFrame(&headersFrame); err != nil {
+ t.Fatal("WriteFrame (HEADERS): ", err)
+ }
+ if err := writer.WriteFrame(&synStreamFrame); err != nil {
+ t.Fatal("WriteFrame (SYN_STREAM): ", err)
+ }
+ }()
+
+ // Read the frames and verify they look as expected.
+ frame, err := reader.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame (HEADERS): ", err)
+ }
+ parsedHeadersFrame, ok := frame.(*HeadersFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type:", frame)
+ }
+ if !reflect.DeepEqual(headersFrame, *parsedHeadersFrame) {
+ t.Fatal("got: ", *parsedHeadersFrame, "\nwant: ", headersFrame)
+ }
+ frame, err = reader.ReadFrame()
+ if err != nil {
+ t.Fatal("ReadFrame (SYN_STREAM):", err)
+ }
+ parsedSynStreamFrame, ok := frame.(*SynStreamFrame)
+ if !ok {
+ t.Fatal("Parsed incorrect frame type.")
+ }
+ if !reflect.DeepEqual(synStreamFrame, *parsedSynStreamFrame) {
+ t.Fatal("got: ", *parsedSynStreamFrame, "\nwant: ", synStreamFrame)
+ }
+}
diff --git a/libgo/go/http/spdy/types.go b/libgo/go/http/spdy/types.go
new file mode 100644
index 00000000000..41cafb1741f
--- /dev/null
+++ b/libgo/go/http/spdy/types.go
@@ -0,0 +1,370 @@
+// 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 spdy
+
+import (
+ "bytes"
+ "compress/zlib"
+ "http"
+ "io"
+ "os"
+)
+
+// Data Frame Format
+// +----------------------------------+
+// |0| Stream-ID (31bits) |
+// +----------------------------------+
+// | flags (8) | Length (24 bits) |
+// +----------------------------------+
+// | Data |
+// +----------------------------------+
+//
+// Control Frame Format
+// +----------------------------------+
+// |1| Version(15bits) | Type(16bits) |
+// +----------------------------------+
+// | flags (8) | Length (24 bits) |
+// +----------------------------------+
+// | Data |
+// +----------------------------------+
+//
+// Control Frame: SYN_STREAM
+// +----------------------------------+
+// |1|000000000000001|0000000000000001|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | >= 12
+// +----------------------------------+
+// |X| Stream-ID(31bits) |
+// +----------------------------------+
+// |X|Associated-To-Stream-ID (31bits)|
+// +----------------------------------+
+// |Pri| unused | Length (16bits)|
+// +----------------------------------+
+//
+// Control Frame: SYN_REPLY
+// +----------------------------------+
+// |1|000000000000001|0000000000000010|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | >= 8
+// +----------------------------------+
+// |X| Stream-ID(31bits) |
+// +----------------------------------+
+// | unused (16 bits)| Length (16bits)|
+// +----------------------------------+
+//
+// Control Frame: RST_STREAM
+// +----------------------------------+
+// |1|000000000000001|0000000000000011|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | >= 4
+// +----------------------------------+
+// |X| Stream-ID(31bits) |
+// +----------------------------------+
+// | Status code (32 bits) |
+// +----------------------------------+
+//
+// Control Frame: SETTINGS
+// +----------------------------------+
+// |1|000000000000001|0000000000000100|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) |
+// +----------------------------------+
+// | # of entries (32) |
+// +----------------------------------+
+//
+// Control Frame: NOOP
+// +----------------------------------+
+// |1|000000000000001|0000000000000101|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | = 0
+// +----------------------------------+
+//
+// Control Frame: PING
+// +----------------------------------+
+// |1|000000000000001|0000000000000110|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | = 4
+// +----------------------------------+
+// | Unique id (32 bits) |
+// +----------------------------------+
+//
+// Control Frame: GOAWAY
+// +----------------------------------+
+// |1|000000000000001|0000000000000111|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | = 4
+// +----------------------------------+
+// |X| Last-accepted-stream-id |
+// +----------------------------------+
+//
+// Control Frame: HEADERS
+// +----------------------------------+
+// |1|000000000000001|0000000000001000|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | >= 8
+// +----------------------------------+
+// |X| Stream-ID (31 bits) |
+// +----------------------------------+
+// | unused (16 bits)| Length (16bits)|
+// +----------------------------------+
+//
+// Control Frame: WINDOW_UPDATE
+// +----------------------------------+
+// |1|000000000000001|0000000000001001|
+// +----------------------------------+
+// | flags (8) | Length (24 bits) | = 8
+// +----------------------------------+
+// |X| Stream-ID (31 bits) |
+// +----------------------------------+
+// | Delta-Window-Size (32 bits) |
+// +----------------------------------+
+
+// Version is the protocol version number that this package implements.
+const Version = 2
+
+// ControlFrameType stores the type field in a control frame header.
+type ControlFrameType uint16
+
+// Control frame type constants
+const (
+ TypeSynStream ControlFrameType = 0x0001
+ TypeSynReply = 0x0002
+ TypeRstStream = 0x0003
+ TypeSettings = 0x0004
+ TypeNoop = 0x0005
+ TypePing = 0x0006
+ TypeGoAway = 0x0007
+ TypeHeaders = 0x0008
+ TypeWindowUpdate = 0x0009
+)
+
+// ControlFlags are the flags that can be set on a control frame.
+type ControlFlags uint8
+
+const (
+ ControlFlagFin ControlFlags = 0x01
+)
+
+// DataFlags are the flags that can be set on a data frame.
+type DataFlags uint8
+
+const (
+ DataFlagFin DataFlags = 0x01
+ DataFlagCompressed = 0x02
+)
+
+// MaxDataLength is the maximum number of bytes that can be stored in one frame.
+const MaxDataLength = 1<<24 - 1
+
+// Frame is a single SPDY frame in its unpacked in-memory representation. Use
+// Framer to read and write it.
+type Frame interface {
+ write(f *Framer) os.Error
+}
+
+// ControlFrameHeader contains all the fields in a control frame header,
+// in its unpacked in-memory representation.
+type ControlFrameHeader struct {
+ // Note, high bit is the "Control" bit.
+ version uint16
+ frameType ControlFrameType
+ Flags ControlFlags
+ length uint32
+}
+
+type controlFrame interface {
+ Frame
+ read(h ControlFrameHeader, f *Framer) os.Error
+}
+
+// SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM
+// frame.
+type SynStreamFrame struct {
+ CFHeader ControlFrameHeader
+ StreamId uint32
+ AssociatedToStreamId uint32
+ // Note, only 2 highest bits currently used
+ // Rest of Priority is unused.
+ Priority uint16
+ Headers http.Header
+}
+
+// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame.
+type SynReplyFrame struct {
+ CFHeader ControlFrameHeader
+ StreamId uint32
+ Headers http.Header
+}
+
+// StatusCode represents the status that led to a RST_STREAM
+type StatusCode uint32
+
+const (
+ ProtocolError StatusCode = 1
+ InvalidStream = 2
+ RefusedStream = 3
+ UnsupportedVersion = 4
+ Cancel = 5
+ InternalError = 6
+ FlowControlError = 7
+)
+
+// RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM
+// frame.
+type RstStreamFrame struct {
+ CFHeader ControlFrameHeader
+ StreamId uint32
+ Status StatusCode
+}
+
+// SettingsFlag represents a flag in a SETTINGS frame.
+type SettingsFlag uint8
+
+const (
+ FlagSettingsPersistValue SettingsFlag = 0x1
+ FlagSettingsPersisted = 0x2
+)
+
+// SettingsFlag represents the id of an id/value pair in a SETTINGS frame.
+type SettingsId uint32
+
+const (
+ SettingsUploadBandwidth SettingsId = 1
+ SettingsDownloadBandwidth = 2
+ SettingsRoundTripTime = 3
+ SettingsMaxConcurrentStreams = 4
+ SettingsCurrentCwnd = 5
+)
+
+// SettingsFlagIdValue is the unpacked, in-memory representation of the
+// combined flag/id/value for a setting in a SETTINGS frame.
+type SettingsFlagIdValue struct {
+ Flag SettingsFlag
+ Id SettingsId
+ Value uint32
+}
+
+// SettingsFrame is the unpacked, in-memory representation of a SPDY
+// SETTINGS frame.
+type SettingsFrame struct {
+ CFHeader ControlFrameHeader
+ FlagIdValues []SettingsFlagIdValue
+}
+
+// NoopFrame is the unpacked, in-memory representation of a NOOP frame.
+type NoopFrame struct {
+ CFHeader ControlFrameHeader
+}
+
+// PingFrame is the unpacked, in-memory representation of a PING frame.
+type PingFrame struct {
+ CFHeader ControlFrameHeader
+ Id uint32
+}
+
+// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame.
+type GoAwayFrame struct {
+ CFHeader ControlFrameHeader
+ LastGoodStreamId uint32
+}
+
+// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame.
+type HeadersFrame struct {
+ CFHeader ControlFrameHeader
+ StreamId uint32
+ Headers http.Header
+}
+
+// DataFrame is the unpacked, in-memory representation of a DATA frame.
+type DataFrame struct {
+ // Note, high bit is the "Control" bit. Should be 0 for data frames.
+ StreamId uint32
+ Flags DataFlags
+ Data []byte
+}
+
+// HeaderDictionary is the dictionary sent to the zlib compressor/decompressor.
+// Even though the specification states there is no null byte at the end, Chrome sends it.
+const HeaderDictionary = "optionsgetheadpostputdeletetrace" +
+ "acceptaccept-charsetaccept-encodingaccept-languageauthorizationexpectfromhost" +
+ "if-modified-sinceif-matchif-none-matchif-rangeif-unmodifiedsince" +
+ "max-forwardsproxy-authorizationrangerefererteuser-agent" +
+ "100101200201202203204205206300301302303304305306307400401402403404405406407408409410411412413414415416417500501502503504505" +
+ "accept-rangesageetaglocationproxy-authenticatepublicretry-after" +
+ "servervarywarningwww-authenticateallowcontent-basecontent-encodingcache-control" +
+ "connectiondatetrailertransfer-encodingupgradeviawarning" +
+ "content-languagecontent-lengthcontent-locationcontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookie" +
+ "MondayTuesdayWednesdayThursdayFridaySaturdaySunday" +
+ "JanFebMarAprMayJunJulAugSepOctNovDec" +
+ "chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" +
+ "charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00"
+
+// A SPDY specific error.
+type ErrorCode string
+
+const (
+ UnlowercasedHeaderName ErrorCode = "header was not lowercased"
+ DuplicateHeaders ErrorCode = "multiple headers with same name"
+ WrongCompressedPayloadSize ErrorCode = "compressed payload size was incorrect"
+ UnknownFrameType ErrorCode = "unknown frame type"
+ InvalidControlFrame ErrorCode = "invalid control frame"
+ InvalidDataFrame ErrorCode = "invalid data frame"
+ InvalidHeaderPresent ErrorCode = "frame contained invalid header"
+)
+
+// Error contains both the type of error and additional values. StreamId is 0
+// if Error is not associated with a stream.
+type Error struct {
+ Err ErrorCode
+ StreamId uint32
+}
+
+func (e *Error) String() string {
+ return string(e.Err)
+}
+
+var invalidReqHeaders = map[string]bool{
+ "Connection": true,
+ "Keep-Alive": true,
+ "Proxy-Connection": true,
+ "Transfer-Encoding": true,
+}
+
+var invalidRespHeaders = map[string]bool{
+ "Connection": true,
+ "Keep-Alive": true,
+ "Transfer-Encoding": true,
+}
+
+// Framer handles serializing/deserializing SPDY frames, including compressing/
+// decompressing payloads.
+type Framer struct {
+ headerCompressionDisabled bool
+ w io.Writer
+ headerBuf *bytes.Buffer
+ headerCompressor *zlib.Writer
+ r io.Reader
+ headerReader io.LimitedReader
+ headerDecompressor io.ReadCloser
+}
+
+// NewFramer allocates a new Framer for a given SPDY connection, repesented by
+// a io.Writer and io.Reader. Note that Framer will read and write individual fields
+// from/to the Reader and Writer, so the caller should pass in an appropriately
+// buffered implementation to optimize performance.
+func NewFramer(w io.Writer, r io.Reader) (*Framer, os.Error) {
+ compressBuf := new(bytes.Buffer)
+ compressor, err := zlib.NewWriterDict(compressBuf, zlib.BestCompression, []byte(HeaderDictionary))
+ if err != nil {
+ return nil, err
+ }
+ framer := &Framer{
+ w: w,
+ headerBuf: compressBuf,
+ headerCompressor: compressor,
+ r: r,
+ }
+ return framer, nil
+}
diff --git a/libgo/go/http/spdy/write.go b/libgo/go/http/spdy/write.go
new file mode 100644
index 00000000000..7d40bbe9fe2
--- /dev/null
+++ b/libgo/go/http/spdy/write.go
@@ -0,0 +1,286 @@
+// 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 spdy
+
+import (
+ "encoding/binary"
+ "http"
+ "io"
+ "os"
+ "strings"
+)
+
+func (frame *SynStreamFrame) write(f *Framer) os.Error {
+ return f.writeSynStreamFrame(frame)
+}
+
+func (frame *SynReplyFrame) write(f *Framer) os.Error {
+ return f.writeSynReplyFrame(frame)
+}
+
+func (frame *RstStreamFrame) write(f *Framer) (err os.Error) {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeRstStream
+ frame.CFHeader.length = 8
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
+ return
+ }
+ return
+}
+
+func (frame *SettingsFrame) write(f *Framer) (err os.Error) {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeSettings
+ frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
+ return
+ }
+ for _, flagIdValue := range frame.FlagIdValues {
+ flagId := (uint32(flagIdValue.Flag) << 24) | uint32(flagIdValue.Id)
+ if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
+ return
+ }
+ }
+ return
+}
+
+func (frame *NoopFrame) write(f *Framer) os.Error {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeNoop
+
+ // Serialize frame to Writer
+ return writeControlFrameHeader(f.w, frame.CFHeader)
+}
+
+func (frame *PingFrame) write(f *Framer) (err os.Error) {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypePing
+ frame.CFHeader.length = 4
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
+ return
+ }
+ return
+}
+
+func (frame *GoAwayFrame) write(f *Framer) (err os.Error) {
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeGoAway
+ frame.CFHeader.length = 4
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
+ return
+ }
+ return nil
+}
+
+func (frame *HeadersFrame) write(f *Framer) os.Error {
+ return f.writeHeadersFrame(frame)
+}
+
+func (frame *DataFrame) write(f *Framer) os.Error {
+ return f.writeDataFrame(frame)
+}
+
+// WriteFrame writes a frame.
+func (f *Framer) WriteFrame(frame Frame) os.Error {
+ return frame.write(f)
+}
+
+func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) os.Error {
+ if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
+ return err
+ }
+ if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
+ return err
+ }
+ flagsAndLength := (uint32(h.Flags) << 24) | h.length
+ if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
+ return err
+ }
+ return nil
+}
+
+func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err os.Error) {
+ n = 0
+ if err = binary.Write(w, binary.BigEndian, uint16(len(h))); err != nil {
+ return
+ }
+ n += 2
+ for name, values := range h {
+ if err = binary.Write(w, binary.BigEndian, uint16(len(name))); err != nil {
+ return
+ }
+ n += 2
+ name = strings.ToLower(name)
+ if _, err = io.WriteString(w, name); err != nil {
+ return
+ }
+ n += len(name)
+ v := strings.Join(values, "\x00")
+ if err = binary.Write(w, binary.BigEndian, uint16(len(v))); err != nil {
+ return
+ }
+ n += 2
+ if _, err = io.WriteString(w, v); err != nil {
+ return
+ }
+ n += len(v)
+ }
+ return
+}
+
+func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err os.Error) {
+ // Marshal the headers.
+ var writer io.Writer = f.headerBuf
+ if !f.headerCompressionDisabled {
+ writer = f.headerCompressor
+ }
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
+ return
+ }
+ if !f.headerCompressionDisabled {
+ f.headerCompressor.Flush()
+ }
+
+ // Set ControlFrameHeader
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeSynStream
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return err
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return err
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
+ return err
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<14); err != nil {
+ return err
+ }
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
+ return err
+ }
+ f.headerBuf.Reset()
+ return nil
+}
+
+func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err os.Error) {
+ // Marshal the headers.
+ var writer io.Writer = f.headerBuf
+ if !f.headerCompressionDisabled {
+ writer = f.headerCompressor
+ }
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
+ return
+ }
+ if !f.headerCompressionDisabled {
+ f.headerCompressor.Flush()
+ }
+
+ // Set ControlFrameHeader
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeSynReply
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
+ return
+ }
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
+ return
+ }
+ f.headerBuf.Reset()
+ return
+}
+
+func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err os.Error) {
+ // Marshal the headers.
+ var writer io.Writer = f.headerBuf
+ if !f.headerCompressionDisabled {
+ writer = f.headerCompressor
+ }
+ if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
+ return
+ }
+ if !f.headerCompressionDisabled {
+ f.headerCompressor.Flush()
+ }
+
+ // Set ControlFrameHeader
+ frame.CFHeader.version = Version
+ frame.CFHeader.frameType = TypeHeaders
+ frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 6)
+
+ // Serialize frame to Writer
+ if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return
+ }
+ if err = binary.Write(f.w, binary.BigEndian, uint16(0)); err != nil {
+ return
+ }
+ if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
+ return
+ }
+ f.headerBuf.Reset()
+ return
+}
+
+func (f *Framer) writeDataFrame(frame *DataFrame) (err os.Error) {
+ // Validate DataFrame
+ if frame.StreamId&0x80000000 != 0 || len(frame.Data) >= 0x0f000000 {
+ return &Error{InvalidDataFrame, frame.StreamId}
+ }
+
+ // Serialize frame to Writer
+ if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
+ return
+ }
+ flagsAndLength := (uint32(frame.Flags) << 24) | uint32(len(frame.Data))
+ if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
+ return
+ }
+ if _, err = f.w.Write(frame.Data); err != nil {
+ return
+ }
+
+ return nil
+}
diff --git a/libgo/go/http/testdata/index.html b/libgo/go/http/testdata/index.html
new file mode 100644
index 00000000000..da8e1e93d15
--- /dev/null
+++ b/libgo/go/http/testdata/index.html
@@ -0,0 +1 @@
+index.html says hello
diff --git a/libgo/go/http/testdata/style.css b/libgo/go/http/testdata/style.css
new file mode 100644
index 00000000000..208d16d4213
--- /dev/null
+++ b/libgo/go/http/testdata/style.css
@@ -0,0 +1 @@
+body {}
diff --git a/libgo/go/http/transfer.go b/libgo/go/http/transfer.go
index 0fa8bed43aa..b65d99a6fd0 100644
--- a/libgo/go/http/transfer.go
+++ b/libgo/go/http/transfer.go
@@ -5,6 +5,7 @@
package http
import (
+ "bytes"
"bufio"
"io"
"io/ioutil"
@@ -17,7 +18,8 @@ import (
// 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
+ Body io.Reader
+ BodyCloser io.Closer
ResponseToHEAD bool
ContentLength int64
Close bool
@@ -33,19 +35,43 @@ func newTransferWriter(r interface{}) (t *transferWriter, err os.Error) {
switch rr := r.(type) {
case *Request:
t.Body = rr.Body
+ t.BodyCloser = rr.Body
t.ContentLength = rr.ContentLength
t.Close = rr.Close
t.TransferEncoding = rr.TransferEncoding
t.Trailer = rr.Trailer
atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
+ if t.Body != nil && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
+ if t.ContentLength == 0 {
+ // Test to see if it's actually zero or just unset.
+ var buf [1]byte
+ n, _ := io.ReadFull(t.Body, buf[:])
+ if n == 1 {
+ // Oh, guess there is data in this Body Reader after all.
+ // The ContentLength field just wasn't set.
+ // Stich the Body back together again, re-attaching our
+ // consumed byte.
+ t.ContentLength = -1
+ t.Body = io.MultiReader(bytes.NewBuffer(buf[:]), t.Body)
+ } else {
+ // Body is actually empty.
+ t.Body = nil
+ t.BodyCloser = nil
+ }
+ }
+ if t.ContentLength < 0 {
+ t.TransferEncoding = []string{"chunked"}
+ }
+ }
case *Response:
t.Body = rr.Body
+ t.BodyCloser = 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)
+ t.ResponseToHEAD = noBodyExpected(rr.Request.Method)
}
// Sanitize Body,ContentLength,TransferEncoding
@@ -95,7 +121,7 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
if err != nil {
return
}
- } else if t.ContentLength > 0 || t.ResponseToHEAD {
+ } else if t.ContentLength > 0 || t.ResponseToHEAD || (t.ContentLength == 0 && isIdentity(t.TransferEncoding)) {
io.WriteString(w, "Content-Length: ")
_, err = io.WriteString(w, strconv.Itoa64(t.ContentLength)+"\r\n")
if err != nil {
@@ -144,7 +170,7 @@ func (t *transferWriter) WriteBody(w io.Writer) (err os.Error) {
if err != nil {
return err
}
- if err = t.Body.Close(); err != nil {
+ if err = t.BodyCloser.Close(); err != nil {
return err
}
}
@@ -192,14 +218,16 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
t := &transferReader{}
// Unify input
+ isResponse := false
switch rr := msg.(type) {
case *Response:
t.Header = rr.Header
t.StatusCode = rr.StatusCode
- t.RequestMethod = rr.RequestMethod
+ t.RequestMethod = rr.Request.Method
t.ProtoMajor = rr.ProtoMajor
t.ProtoMinor = rr.ProtoMinor
t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
+ isResponse = true
case *Request:
t.Header = rr.Header
t.ProtoMajor = rr.ProtoMajor
@@ -208,6 +236,8 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
// Responses with status code 200, responding to a GET method
t.StatusCode = 200
t.RequestMethod = "GET"
+ default:
+ panic("unexpected type")
}
// Default to HTTP/1.1
@@ -221,7 +251,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
return err
}
- t.ContentLength, err = fixLength(t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
+ t.ContentLength, err = fixLength(isResponse, t.StatusCode, t.RequestMethod, t.Header, t.TransferEncoding)
if err != nil {
return err
}
@@ -249,7 +279,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
// 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}
+ 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}
@@ -262,9 +292,6 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
// 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
@@ -289,6 +316,9 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
// Checks whether chunked is part of the encodings stack
func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
+// Checks whether the encoding is explicitly "identity".
+func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
+
// Sanitize transfer encoding
func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Error) {
raw, present := header["Transfer-Encoding"]
@@ -304,7 +334,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Erro
return nil, nil
}
- encodings := strings.Split(raw[0], ",", -1)
+ encodings := strings.Split(raw[0], ",")
te := make([]string, 0, len(encodings))
// TODO: Even though we only support "identity" and "chunked"
// encodings, the loop below is designed with foresight. One
@@ -339,7 +369,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, os.Erro
// 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 Header, te []string) (int64, os.Error) {
+func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, os.Error) {
// Logic based on response type or status
if noBodyExpected(requestMethod) {
@@ -370,6 +400,14 @@ func fixLength(status int, requestMethod string, header Header, te []string) (in
header.Del("Content-Length")
}
+ if !isResponse && requestMethod == "GET" {
+ // RFC 2616 doesn't explicitly permit nor forbid an
+ // entity-body on a GET request so we permit one if
+ // declared, but we default to 0 here (not -1 below)
+ // if there's no mention of a body.
+ return 0, nil
+ }
+
// 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.
@@ -412,7 +450,7 @@ func fixTrailer(header Header, te []string) (Header, os.Error) {
header.Del("Trailer")
trailer := make(Header)
- keys := strings.Split(raw, ",", -1)
+ keys := strings.Split(raw, ",")
for _, key := range keys {
key = CanonicalHeaderKey(strings.TrimSpace(key))
switch key {
diff --git a/libgo/go/http/transport.go b/libgo/go/http/transport.go
index 73a2c2191ea..4302ffab1e3 100644
--- a/libgo/go/http/transport.go
+++ b/libgo/go/http/transport.go
@@ -6,17 +6,18 @@ package http
import (
"bufio"
- "bytes"
"compress/gzip"
"crypto/tls"
"encoding/base64"
"fmt"
"io"
+ "io/ioutil"
"log"
"net"
"os"
"strings"
"sync"
+ "url"
)
// DefaultTransport is the default implementation of Transport and is
@@ -24,7 +25,7 @@ import (
// each call to Do and uses HTTP proxies as directed by the
// $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy)
// environment variables.
-var DefaultTransport RoundTripper = &Transport{}
+var DefaultTransport RoundTripper = &Transport{Proxy: ProxyFromEnvironment}
// DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost.
@@ -36,12 +37,23 @@ const DefaultMaxIdleConnsPerHost = 2
type Transport struct {
lk sync.Mutex
idleConn map[string][]*persistConn
+ altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
// TODO: tunable on global max cached connections
// TODO: tunable on timeout on cached connections
// TODO: optional pipelining
- IgnoreEnvironment bool // don't look at environment variables for proxy configuration
+ // Proxy specifies a function to return a proxy for a given
+ // Request. If the function returns a non-nil error, the
+ // request is aborted with the provided error.
+ // If Proxy is nil or returns a nil *URL, no proxy is used.
+ Proxy func(*Request) (*url.URL, os.Error)
+
+ // Dial specifies the dial function for creating TCP
+ // connections.
+ // If Dial is nil, net.Dial is used.
+ Dial func(net, addr string) (c net.Conn, err os.Error)
+
DisableKeepAlives bool
DisableCompression bool
@@ -51,15 +63,57 @@ type Transport struct {
MaxIdleConnsPerHost int
}
+// ProxyFromEnvironment returns the URL of the proxy to use for a
+// given request, as indicated by the environment variables
+// $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy).
+// Either URL or an error is returned.
+func ProxyFromEnvironment(req *Request) (*url.URL, os.Error) {
+ proxy := getenvEitherCase("HTTP_PROXY")
+ if proxy == "" {
+ return nil, nil
+ }
+ if !useProxy(canonicalAddr(req.URL)) {
+ return nil, nil
+ }
+ proxyURL, err := url.ParseRequest(proxy)
+ if err != nil {
+ return nil, os.NewError("invalid proxy address")
+ }
+ if proxyURL.Host == "" {
+ proxyURL, err = url.ParseRequest("http://" + proxy)
+ if err != nil {
+ return nil, os.NewError("invalid proxy address")
+ }
+ }
+ return proxyURL, nil
+}
+
+// ProxyURL returns a proxy function (for use in a Transport)
+// that always returns the same URL.
+func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, os.Error) {
+ return func(*Request) (*url.URL, os.Error) {
+ return fixedURL, nil
+ }
+}
+
// RoundTrip implements the RoundTripper interface.
func (t *Transport) RoundTrip(req *Request) (resp *Response, err os.Error) {
if req.URL == nil {
- if req.URL, err = ParseURL(req.RawURL); err != nil {
+ if req.URL, err = url.Parse(req.RawURL); err != nil {
return
}
}
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
- return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
+ t.lk.Lock()
+ var rt RoundTripper
+ if t.altProto != nil {
+ rt = t.altProto[req.URL.Scheme]
+ }
+ t.lk.Unlock()
+ if rt == nil {
+ return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
+ }
+ return rt.RoundTrip(req)
}
cm, err := t.connectMethodForRequest(req)
@@ -79,6 +133,27 @@ func (t *Transport) RoundTrip(req *Request) (resp *Response, err os.Error) {
return pconn.roundTrip(req)
}
+// RegisterProtocol registers a new protocol with scheme.
+// The Transport will pass requests using the given scheme to rt.
+// It is rt's responsibility to simulate HTTP request semantics.
+//
+// RegisterProtocol can be used by other packages to provide
+// implementations of protocol schemes like "ftp" or "file".
+func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) {
+ if scheme == "http" || scheme == "https" {
+ panic("protocol " + scheme + " already registered")
+ }
+ t.lk.Lock()
+ defer t.lk.Unlock()
+ if t.altProto == nil {
+ t.altProto = make(map[string]RoundTripper)
+ }
+ if _, exists := t.altProto[scheme]; exists {
+ panic("protocol " + scheme + " already registered")
+ }
+ t.altProto[scheme] = rt
+}
+
// CloseIdleConnections closes any connections which were previously
// connected from previous requests but are now sitting idle in
// a "keep-alive" state. It does not interrupt any connections currently
@@ -101,21 +176,11 @@ func (t *Transport) CloseIdleConnections() {
// Private implementation past this point.
//
-func (t *Transport) getenvEitherCase(k string) string {
- if t.IgnoreEnvironment {
- return ""
- }
- if v := t.getenv(strings.ToUpper(k)); v != "" {
+func getenvEitherCase(k string) string {
+ if v := os.Getenv(strings.ToUpper(k)); v != "" {
return v
}
- return t.getenv(strings.ToLower(k))
-}
-
-func (t *Transport) getenv(k string) string {
- if t.IgnoreEnvironment {
- return ""
- }
- return os.Getenv(k)
+ return os.Getenv(strings.ToLower(k))
}
func (t *Transport) connectMethodForRequest(req *Request) (*connectMethod, os.Error) {
@@ -123,20 +188,12 @@ func (t *Transport) connectMethodForRequest(req *Request) (*connectMethod, os.Er
targetScheme: req.URL.Scheme,
targetAddr: canonicalAddr(req.URL),
}
-
- proxy := t.getenvEitherCase("HTTP_PROXY")
- if proxy != "" && t.useProxy(cm.targetAddr) {
- proxyURL, err := ParseRequestURL(proxy)
+ if t.Proxy != nil {
+ var err os.Error
+ cm.proxyURL, err = t.Proxy(req)
if err != nil {
- return nil, os.ErrorString("invalid proxy address")
- }
- if proxyURL.Host == "" {
- proxyURL, err = ParseRequestURL("http://" + proxy)
- if err != nil {
- return nil, os.ErrorString("invalid proxy address")
- }
+ return nil, err
}
- cm.proxyURL = proxyURL
}
return cm, nil
}
@@ -149,10 +206,7 @@ func (cm *connectMethod) proxyAuth() string {
}
proxyInfo := cm.proxyURL.RawUserinfo
if proxyInfo != "" {
- enc := base64.URLEncoding
- encoded := make([]byte, enc.EncodedLen(len(proxyInfo)))
- enc.Encode(encoded, []byte(proxyInfo))
- return "Basic " + string(encoded)
+ return "Basic " + base64.URLEncoding.EncodeToString([]byte(proxyInfo))
}
return ""
}
@@ -207,6 +261,13 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
return
}
+func (t *Transport) dial(network, addr string) (c net.Conn, err os.Error) {
+ if t.Dial != nil {
+ return t.Dial(network, addr)
+ }
+ return net.Dial(network, addr)
+}
+
// getConn dials and creates a new persistConn to the target as
// specified in the connectMethod. This includes doing a proxy CONNECT
// and/or setting up TLS. If this doesn't return an error, the persistConn
@@ -216,7 +277,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
return pc, nil
}
- conn, err := net.Dial("tcp", cm.addr())
+ conn, err := t.dial("tcp", cm.addr())
if err != nil {
if cm.proxyURL != nil {
err = fmt.Errorf("http: error connecting to proxy %s: %v", cm.proxyURL, err)
@@ -248,26 +309,30 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
}
}
case cm.targetScheme == "https":
- fmt.Fprintf(conn, "CONNECT %s HTTP/1.1\r\n", cm.targetAddr)
- fmt.Fprintf(conn, "Host: %s\r\n", cm.targetAddr)
+ connectReq := &Request{
+ Method: "CONNECT",
+ RawURL: cm.targetAddr,
+ Host: cm.targetAddr,
+ Header: make(Header),
+ }
if pa != "" {
- fmt.Fprintf(conn, "Proxy-Authorization: %s\r\n", pa)
+ connectReq.Header.Set("Proxy-Authorization", pa)
}
- fmt.Fprintf(conn, "\r\n")
+ connectReq.Write(conn)
// Read response.
// Okay to use and discard buffered reader here, because
// TLS server will not speak until spoken to.
br := bufio.NewReader(conn)
- resp, err := ReadResponse(br, "CONNECT")
+ resp, err := ReadResponse(br, connectReq)
if err != nil {
conn.Close()
return nil, err
}
if resp.StatusCode != 200 {
- f := strings.Split(resp.Status, " ", 2)
+ f := strings.SplitN(resp.Status, " ", 2)
conn.Close()
- return nil, os.ErrorString(f[1])
+ return nil, os.NewError(f[1])
}
}
@@ -285,7 +350,6 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
pconn.br = bufio.NewReader(pconn.conn)
pconn.cc = newClientConnFunc(conn, pconn.br)
- pconn.cc.readRes = readResponseWithEOFSignal
go pconn.readLoop()
return pconn, nil
}
@@ -293,7 +357,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
// useProxy returns true if requests to addr should use a proxy,
// according to the NO_PROXY or no_proxy environment variable.
// addr is always a canonicalAddr with a host and port.
-func (t *Transport) useProxy(addr string) bool {
+func useProxy(addr string) bool {
if len(addr) == 0 {
return true
}
@@ -305,16 +369,12 @@ func (t *Transport) useProxy(addr string) bool {
return false
}
if ip := net.ParseIP(host); ip != nil {
- if ip4 := ip.To4(); ip4 != nil && ip4[0] == 127 {
- // 127.0.0.0/8 loopback isn't proxied.
- return false
- }
- if bytes.Equal(ip, net.IPv6loopback) {
+ if ip.IsLoopback() {
return false
}
}
- no_proxy := t.getenvEitherCase("NO_PROXY")
+ no_proxy := getenvEitherCase("NO_PROXY")
if no_proxy == "*" {
return false
}
@@ -324,7 +384,7 @@ func (t *Transport) useProxy(addr string) bool {
addr = addr[:strings.LastIndex(addr, ":")]
}
- for _, p := range strings.Split(no_proxy, ",", -1) {
+ for _, p := range strings.Split(no_proxy, ",") {
p = strings.ToLower(strings.TrimSpace(p))
if len(p) == 0 {
continue
@@ -354,9 +414,9 @@ func (t *Transport) useProxy(addr string) bool {
// Note: no support to https to the proxy yet.
//
type connectMethod struct {
- proxyURL *URL // "" for no proxy, else full proxy URL
- targetScheme string // "http" or "https"
- targetAddr string // Not used if proxy + http targetScheme (4th example in table)
+ proxyURL *url.URL // nil for no proxy, else full proxy URL
+ targetScheme string // "http" or "https"
+ targetAddr string // Not used if proxy + http targetScheme (4th example in table)
}
func (ck *connectMethod) String() string {
@@ -447,7 +507,28 @@ func (pc *persistConn) readLoop() {
}
rc := <-pc.reqch
- resp, err := pc.cc.Read(rc.req)
+ resp, err := pc.cc.readUsing(rc.req, func(buf *bufio.Reader, forReq *Request) (*Response, os.Error) {
+ resp, err := ReadResponse(buf, forReq)
+ if err != nil || resp.ContentLength == 0 {
+ return resp, err
+ }
+ if rc.addedGzip {
+ forReq.Header.Del("Accept-Encoding")
+ }
+ if rc.addedGzip && resp.Header.Get("Content-Encoding") == "gzip" {
+ resp.Header.Del("Content-Encoding")
+ resp.Header.Del("Content-Length")
+ resp.ContentLength = -1
+ gzReader, err := gzip.NewReader(resp.Body)
+ if err != nil {
+ pc.close()
+ return nil, err
+ }
+ resp.Body = &readFirstCloseBoth{&discardOnCloseReadCloser{gzReader}, resp.Body}
+ }
+ resp.Body = &bodyEOFSignal{body: resp.Body}
+ return resp, err
+ })
if err == ErrPersistEOF {
// Succeeded, but we can't send any more
@@ -469,6 +550,17 @@ func (pc *persistConn) readLoop() {
waitForBodyRead <- true
}
} else {
+ // When there's no response body, we immediately
+ // reuse the TCP connection (putIdleConn), but
+ // we need to prevent ClientConn.Read from
+ // closing the Response.Body on the next
+ // loop, otherwise it might close the body
+ // before the client code has had a chance to
+ // read it (even though it'll just be 0, EOF).
+ pc.cc.lk.Lock()
+ pc.cc.lastbody = nil
+ pc.cc.lk.Unlock()
+
pc.t.putIdleConn(pc)
}
}
@@ -491,6 +583,11 @@ type responseAndError struct {
type requestAndChan struct {
req *Request
ch chan responseAndError
+
+ // did the Transport (as opposed to the client code) add an
+ // Accept-Encoding gzip header? only if it we set it do
+ // we transparently decode the gzip.
+ addedGzip bool
}
func (pc *persistConn) roundTrip(req *Request) (resp *Response, err os.Error) {
@@ -522,25 +619,12 @@ func (pc *persistConn) roundTrip(req *Request) (resp *Response, err os.Error) {
}
ch := make(chan responseAndError, 1)
- pc.reqch <- requestAndChan{req, ch}
+ pc.reqch <- requestAndChan{req, ch, requestedGzip}
re := <-ch
pc.lk.Lock()
pc.numExpectedResponses--
pc.lk.Unlock()
- if re.err == nil && requestedGzip && re.res.Header.Get("Content-Encoding") == "gzip" {
- re.res.Header.Del("Content-Encoding")
- re.res.Header.Del("Content-Length")
- re.res.ContentLength = -1
- esb := re.res.Body.(*bodyEOFSignal)
- gzReader, err := gzip.NewReader(esb.body)
- if err != nil {
- pc.close()
- return nil, err
- }
- esb.body = &readFirstCloseBoth{gzReader, esb.body}
- }
-
return re.res, re.err
}
@@ -559,7 +643,7 @@ var portMap = map[string]string{
}
// canonicalAddr returns url.Host but always with a ":port" suffix
-func canonicalAddr(url *URL) string {
+func canonicalAddr(url *url.URL) string {
addr := url.Host
if !hasPort(addr) {
return addr + ":" + portMap[url.Scheme]
@@ -572,16 +656,6 @@ func responseIsKeepAlive(res *Response) bool {
return false
}
-// readResponseWithEOFSignal is a wrapper around ReadResponse that replaces
-// the response body with a bodyEOFSignal-wrapped version.
-func readResponseWithEOFSignal(r *bufio.Reader, requestMethod string) (resp *Response, err os.Error) {
- resp, err = ReadResponse(r, requestMethod)
- if err == nil && resp.ContentLength != 0 {
- resp.Body = &bodyEOFSignal{body: resp.Body}
- }
- return
-}
-
// bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
// once, right before the final Read() or Close() call returns, but after
// EOF has been seen.
@@ -604,6 +678,9 @@ func (es *bodyEOFSignal) Read(p []byte) (n int, err os.Error) {
}
func (es *bodyEOFSignal) Close() (err os.Error) {
+ if es.isClosed {
+ return nil
+ }
es.isClosed = true
err = es.body.Close()
if err == nil && es.fn != nil {
@@ -628,3 +705,13 @@ func (r *readFirstCloseBoth) Close() os.Error {
}
return nil
}
+
+// discardOnCloseReadCloser consumes all its input on Close.
+type discardOnCloseReadCloser struct {
+ io.ReadCloser
+}
+
+func (d *discardOnCloseReadCloser) Close() os.Error {
+ io.Copy(ioutil.Discard, d.ReadCloser) // ignore errors; likely invalid or already closed
+ return d.ReadCloser.Close()
+}
diff --git a/libgo/go/http/transport_test.go b/libgo/go/http/transport_test.go
index 7610856738d..eafde7f8995 100644
--- a/libgo/go/http/transport_test.go
+++ b/libgo/go/http/transport_test.go
@@ -17,8 +17,10 @@ import (
"io/ioutil"
"os"
"strconv"
+ "strings"
"testing"
"time"
+ "url"
)
// TODO: test 5 pipelined requests with responses: 1) OK, 2) OK, Connection: Close
@@ -43,7 +45,7 @@ func TestTransportKeepAlives(t *testing.T) {
c := &Client{Transport: tr}
fetch := func(n int) string {
- res, _, err := c.Get(ts.URL)
+ res, err := c.Get(ts.URL)
if err != nil {
t.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive, n, err)
}
@@ -76,7 +78,7 @@ func TestTransportConnectionCloseOnResponse(t *testing.T) {
fetch := func(n int) string {
req := new(Request)
var err os.Error
- req.URL, err = ParseURL(ts.URL + fmt.Sprintf("?close=%v", connectionClose))
+ req.URL, err = url.Parse(ts.URL + fmt.Sprintf("?close=%v", connectionClose))
if err != nil {
t.Fatalf("URL parse error: %v", err)
}
@@ -118,7 +120,7 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
fetch := func(n int) string {
req := new(Request)
var err os.Error
- req.URL, err = ParseURL(ts.URL)
+ req.URL, err = url.Parse(ts.URL)
if err != nil {
t.Fatalf("URL parse error: %v", err)
}
@@ -160,7 +162,7 @@ func TestTransportIdleCacheKeys(t *testing.T) {
t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
}
- resp, _, err := c.Get(ts.URL)
+ resp, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
}
@@ -201,7 +203,7 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
// Their responses will hang until we we write to resch, though.
donech := make(chan bool)
doReq := func() {
- resp, _, err := c.Get(ts.URL)
+ resp, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
}
@@ -266,7 +268,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
}
for retries >= 0 {
retries--
- res, _, err := c.Get(ts.URL)
+ res, err := c.Get(ts.URL)
if err != nil {
condFatalf("error in req #%d, GET: %v", n, err)
continue
@@ -386,6 +388,68 @@ func TestTransportNilURL(t *testing.T) {
}
}
+var roundTripTests = []struct {
+ accept string
+ expectAccept string
+ compressed bool
+}{
+ // Requests with no accept-encoding header use transparent compression
+ {"", "gzip", false},
+ // Requests with other accept-encoding should pass through unmodified
+ {"foo", "foo", false},
+ // Requests with accept-encoding == gzip should be passed through
+ {"gzip", "gzip", true}}
+
+// Test that the modification made to the Request by the RoundTripper is cleaned up
+func TestRoundTripGzip(t *testing.T) {
+ const responseBody = "test response body"
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ accept := req.Header.Get("Accept-Encoding")
+ if expect := req.FormValue("expect_accept"); accept != expect {
+ t.Errorf("Accept-Encoding = %q, want %q", accept, expect)
+ }
+ if accept == "gzip" {
+ rw.Header().Set("Content-Encoding", "gzip")
+ gz, _ := gzip.NewWriter(rw)
+ gz.Write([]byte(responseBody))
+ gz.Close()
+ } else {
+ rw.Header().Set("Content-Encoding", accept)
+ rw.Write([]byte(responseBody))
+ }
+ }))
+ defer ts.Close()
+
+ for i, test := range roundTripTests {
+ // Test basic request (no accept-encoding)
+ req, _ := NewRequest("GET", ts.URL+"?expect_accept="+test.expectAccept, nil)
+ req.Header.Set("Accept-Encoding", test.accept)
+ res, err := DefaultTransport.RoundTrip(req)
+ var body []byte
+ if test.compressed {
+ gzip, _ := gzip.NewReader(res.Body)
+ body, err = ioutil.ReadAll(gzip)
+ res.Body.Close()
+ } else {
+ body, err = ioutil.ReadAll(res.Body)
+ }
+ if err != nil {
+ t.Errorf("%d. Error: %q", i, err)
+ } else {
+ if g, e := string(body), responseBody; g != e {
+ t.Errorf("%d. body = %q; want %q", i, g, e)
+ }
+ if g, e := req.Header.Get("Accept-Encoding"), test.accept; g != e {
+ t.Errorf("%d. Accept-Encoding = %q; want %q", i, g, e)
+ }
+ if g, e := res.Header.Get("Content-Encoding"), test.accept; g != e {
+ t.Errorf("%d. Content-Encoding = %q; want %q", i, g, e)
+ }
+ }
+ }
+
+}
+
func TestTransportGzip(t *testing.T) {
const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
const nRandBytes = 1024 * 1024
@@ -394,6 +458,9 @@ func TestTransportGzip(t *testing.T) {
t.Errorf("Accept-Encoding = %q, want %q", g, e)
}
rw.Header().Set("Content-Encoding", "gzip")
+ if req.Method == "HEAD" {
+ return
+ }
var w io.Writer = rw
var buf bytes.Buffer
@@ -417,7 +484,7 @@ func TestTransportGzip(t *testing.T) {
c := &Client{Transport: &Transport{}}
// First fetch something large, but only read some of it.
- res, _, err := c.Get(ts.URL + "?body=large&chunked=" + chunked)
+ res, err := c.Get(ts.URL + "?body=large&chunked=" + chunked)
if err != nil {
t.Fatalf("large get: %v", err)
}
@@ -437,7 +504,7 @@ func TestTransportGzip(t *testing.T) {
}
// Then something small.
- res, _, err = c.Get(ts.URL + "?chunked=" + chunked)
+ res, err = c.Get(ts.URL + "?chunked=" + chunked)
if err != nil {
t.Fatal(err)
}
@@ -463,6 +530,40 @@ func TestTransportGzip(t *testing.T) {
t.Errorf("expected Read error after Close; got %d, %v", n, err)
}
}
+
+ // And a HEAD request too, because they're always weird.
+ c := &Client{Transport: &Transport{}}
+ res, err := c.Head(ts.URL)
+ if err != nil {
+ t.Fatalf("Head: %v", err)
+ }
+ if res.StatusCode != 200 {
+ t.Errorf("Head status=%d; want=200", res.StatusCode)
+ }
+}
+
+func TestTransportProxy(t *testing.T) {
+ ch := make(chan string, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ch <- "real server"
+ }))
+ defer ts.Close()
+ proxy := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ch <- "proxy for " + r.URL.String()
+ }))
+ defer proxy.Close()
+
+ pu, err := url.Parse(proxy.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ c := &Client{Transport: &Transport{Proxy: ProxyURL(pu)}}
+ c.Head(ts.URL)
+ got := <-ch
+ want := "proxy for " + ts.URL + "/"
+ if got != want {
+ t.Errorf("want %q, got %q", want, got)
+ }
}
// TestTransportGzipRecursive sends a gzip quine and checks that the
@@ -477,7 +578,7 @@ func TestTransportGzipRecursive(t *testing.T) {
defer ts.Close()
c := &Client{Transport: &Transport{}}
- res, _, err := c.Get(ts.URL)
+ res, err := c.Get(ts.URL)
if err != nil {
t.Fatal(err)
}
@@ -494,6 +595,36 @@ func TestTransportGzipRecursive(t *testing.T) {
}
}
+type fooProto struct{}
+
+func (fooProto) RoundTrip(req *Request) (*Response, os.Error) {
+ res := &Response{
+ Status: "200 OK",
+ StatusCode: 200,
+ Header: make(Header),
+ Body: ioutil.NopCloser(strings.NewReader("You wanted " + req.URL.String())),
+ }
+ return res, nil
+}
+
+func TestTransportAltProto(t *testing.T) {
+ tr := &Transport{}
+ c := &Client{Transport: tr}
+ tr.RegisterProtocol("foo", fooProto{})
+ res, err := c.Get("foo://bar.com/path")
+ if err != nil {
+ t.Fatal(err)
+ }
+ bodyb, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ body := string(bodyb)
+ if e := "You wanted foo://bar.com/path"; body != e {
+ t.Errorf("got response %q, want %q", body, e)
+ }
+}
+
// rgz is a gzip quine that uncompresses to itself.
var rgz = []byte{
0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
diff --git a/libgo/go/image/bmp/reader.go b/libgo/go/image/bmp/reader.go
new file mode 100644
index 00000000000..357da1dacdc
--- /dev/null
+++ b/libgo/go/image/bmp/reader.go
@@ -0,0 +1,151 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bmp implements a BMP image decoder.
+//
+// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
+package bmp
+
+import (
+ "image"
+ "io"
+ "os"
+)
+
+// ErrUnsupported means that the input BMP image uses a valid but unsupported
+// feature.
+var ErrUnsupported = os.NewError("bmp: unsupported BMP image")
+
+func readUint16(b []byte) uint16 {
+ return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func readUint32(b []byte) uint32 {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+// decodePaletted reads an 8 bit-per-pixel BMP image from r.
+func decodePaletted(r io.Reader, c image.Config) (image.Image, os.Error) {
+ var tmp [4]byte
+ paletted := image.NewPaletted(c.Width, c.Height, c.ColorModel.(image.PalettedColorModel))
+ // BMP images are stored bottom-up rather than top-down.
+ for y := c.Height - 1; y >= 0; y-- {
+ p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
+ _, err := io.ReadFull(r, p)
+ if err != nil {
+ return nil, err
+ }
+ // Each row is 4-byte aligned.
+ if c.Width%4 != 0 {
+ _, err := io.ReadFull(r, tmp[:4-c.Width%4])
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return paletted, nil
+}
+
+// decodeRGBA reads a 24 bit-per-pixel BMP image from r.
+func decodeRGBA(r io.Reader, c image.Config) (image.Image, os.Error) {
+ rgba := image.NewRGBA(c.Width, c.Height)
+ // There are 3 bytes per pixel, and each row is 4-byte aligned.
+ b := make([]byte, (3*c.Width+3)&^3)
+ // BMP images are stored bottom-up rather than top-down.
+ for y := c.Height - 1; y >= 0; y-- {
+ _, err := io.ReadFull(r, b)
+ if err != nil {
+ return nil, err
+ }
+ p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
+ for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
+ // BMP images are stored in BGR order rather than RGB order.
+ p[i+0] = b[j+2]
+ p[i+1] = b[j+1]
+ p[i+2] = b[j+0]
+ p[i+3] = 0xFF
+ }
+ }
+ return rgba, nil
+}
+
+// Decode reads a BMP image from r and returns it as an image.Image.
+// Limitation: The file must be 8 or 24 bits per pixel.
+func Decode(r io.Reader) (image.Image, os.Error) {
+ c, err := DecodeConfig(r)
+ if err != nil {
+ return nil, err
+ }
+ if c.ColorModel == image.RGBAColorModel {
+ return decodeRGBA(r, c)
+ }
+ return decodePaletted(r, c)
+}
+
+// DecodeConfig returns the color model and dimensions of a BMP image without
+// decoding the entire image.
+// Limitation: The file must be 8 or 24 bits per pixel.
+func DecodeConfig(r io.Reader) (config image.Config, err os.Error) {
+ // We only support those BMP images that are a BITMAPFILEHEADER
+ // immediately followed by a BITMAPINFOHEADER.
+ const (
+ fileHeaderLen = 14
+ infoHeaderLen = 40
+ )
+ var b [1024]byte
+ if _, err = io.ReadFull(r, b[:fileHeaderLen+infoHeaderLen]); err != nil {
+ return
+ }
+ if string(b[:2]) != "BM" {
+ err = os.NewError("bmp: invalid format")
+ return
+ }
+ offset := readUint32(b[10:14])
+ if readUint32(b[14:18]) != infoHeaderLen {
+ err = ErrUnsupported
+ return
+ }
+ width := int(readUint32(b[18:22]))
+ height := int(readUint32(b[22:26]))
+ if width < 0 || height < 0 {
+ err = ErrUnsupported
+ return
+ }
+ // We only support 1 plane, 8 or 24 bits per pixel and no compression.
+ planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
+ if planes != 1 || compression != 0 {
+ err = ErrUnsupported
+ return
+ }
+ switch bpp {
+ case 8:
+ if offset != fileHeaderLen+infoHeaderLen+256*4 {
+ err = ErrUnsupported
+ return
+ }
+ _, err = io.ReadFull(r, b[:256*4])
+ if err != nil {
+ return
+ }
+ pcm := make(image.PalettedColorModel, 256)
+ for i := range pcm {
+ // BMP images are stored in BGR order rather than RGB order.
+ // Every 4th byte is padding.
+ pcm[i] = image.RGBAColor{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF}
+ }
+ return image.Config{pcm, width, height}, nil
+ case 24:
+ if offset != fileHeaderLen+infoHeaderLen {
+ err = ErrUnsupported
+ return
+ }
+ return image.Config{image.RGBAColorModel, width, height}, nil
+ }
+ err = ErrUnsupported
+ return
+}
+
+func init() {
+ image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig)
+}
diff --git a/libgo/go/image/color.go b/libgo/go/image/color.go
index c1345c0252c..501a882f02e 100644
--- a/libgo/go/image/color.go
+++ b/libgo/go/image/color.go
@@ -4,14 +4,14 @@
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].
+// Color can convert itself to alpha-premultiplied RGBA, with a possible loss
+// of precision. Each value ranges within [0, 0xFFFF], but is represented by a
+// uint32 so that multiplying by a blend factor up to 0xFFFF will not overflow.
type Color interface {
RGBA() (r, g, b, a uint32)
}
-// An RGBAColor represents a traditional 32-bit alpha-premultiplied color,
+// 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
@@ -29,7 +29,7 @@ func (c RGBAColor) RGBA() (r, g, b, a uint32) {
return
}
-// An RGBA64Color represents a 64-bit alpha-premultiplied color,
+// 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
@@ -39,7 +39,7 @@ 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.
+// NRGBAColor represents a non-alpha-premultiplied 32-bit color.
type NRGBAColor struct {
R, G, B, A uint8
}
@@ -62,7 +62,7 @@ func (c NRGBAColor) RGBA() (r, g, b, a uint32) {
return
}
-// An NRGBA64Color represents a non-alpha-premultiplied 64-bit color,
+// 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
@@ -82,7 +82,7 @@ func (c NRGBA64Color) RGBA() (r, g, b, a uint32) {
return
}
-// An AlphaColor represents an 8-bit alpha.
+// AlphaColor represents an 8-bit alpha.
type AlphaColor struct {
A uint8
}
@@ -93,7 +93,7 @@ func (c AlphaColor) RGBA() (r, g, b, a uint32) {
return a, a, a, a
}
-// An Alpha16Color represents a 16-bit alpha.
+// Alpha16Color represents a 16-bit alpha.
type Alpha16Color struct {
A uint16
}
@@ -103,7 +103,7 @@ func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
return a, a, a, a
}
-// A GrayColor represents an 8-bit grayscale color.
+// GrayColor represents an 8-bit grayscale color.
type GrayColor struct {
Y uint8
}
@@ -114,7 +114,7 @@ func (c GrayColor) RGBA() (r, g, b, a uint32) {
return y, y, y, 0xffff
}
-// A Gray16Color represents a 16-bit grayscale color.
+// Gray16Color represents a 16-bit grayscale color.
type Gray16Color struct {
Y uint16
}
@@ -124,7 +124,7 @@ func (c Gray16Color) RGBA() (r, g, b, a uint32) {
return y, y, y, 0xffff
}
-// A ColorModel can convert foreign Colors, with a possible loss of precision,
+// 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
diff --git a/libgo/go/image/decode_test.go b/libgo/go/image/decode_test.go
index fee537cf1a2..540d5eda5c2 100644
--- a/libgo/go/image/decode_test.go
+++ b/libgo/go/image/decode_test.go
@@ -10,29 +10,34 @@ import (
"os"
"testing"
- // TODO(nigeltao): implement bmp decoder.
+ _ "image/bmp"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
_ "image/tiff"
)
-const goldenFile = "testdata/video-001.png"
-
type imageTest struct {
- filename string
- tolerance int
+ goldenFilename string
+ filename string
+ tolerance int
}
var imageTests = []imageTest{
- //{"testdata/video-001.bmp", 0},
+ {"testdata/video-001.png", "testdata/video-001.bmp", 0},
// GIF images are restricted to a 256-color palette and the conversion
// to GIF loses significant image quality.
- {"testdata/video-001.gif", 64 << 8},
+ {"testdata/video-001.png", "testdata/video-001.gif", 64 << 8},
+ {"testdata/video-001.png", "testdata/video-001.interlaced.gif", 64 << 8},
+ {"testdata/video-001.png", "testdata/video-001.5bpp.gif", 128 << 8},
// JPEG is a lossy format and hence needs a non-zero tolerance.
- {"testdata/video-001.jpeg", 8 << 8},
- {"testdata/video-001.png", 0},
- {"testdata/video-001.tiff", 0},
+ {"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
+ {"testdata/video-001.png", "testdata/video-001.png", 0},
+ {"testdata/video-001.png", "testdata/video-001.tiff", 0},
+
+ // Test grayscale images.
+ {"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
+ {"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
}
func decode(filename string) (image.Image, string, os.Error) {
@@ -44,6 +49,15 @@ func decode(filename string) (image.Image, string, os.Error) {
return image.Decode(bufio.NewReader(f))
}
+func decodeConfig(filename string) (image.Config, string, os.Error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return image.Config{}, "", err
+ }
+ defer f.Close()
+ return image.DecodeConfig(bufio.NewReader(f))
+}
+
func delta(u0, u1 uint32) int {
d := int(u0) - int(u1)
if d < 0 {
@@ -63,29 +77,47 @@ func withinTolerance(c0, c1 image.Color, tolerance int) bool {
}
func TestDecode(t *testing.T) {
- golden, _, err := decode(goldenFile)
- if err != nil {
- t.Errorf("%s: %v", goldenFile, err)
- }
+ golden := make(map[string]image.Image)
loop:
for _, it := range imageTests {
- m, _, err := decode(it.filename)
+ g := golden[it.goldenFilename]
+ if g == nil {
+ var err os.Error
+ g, _, err = decode(it.goldenFilename)
+ if err != nil {
+ t.Errorf("%s: %v", it.goldenFilename, err)
+ continue loop
+ }
+ golden[it.goldenFilename] = g
+ }
+ m, imageFormat, err := decode(it.filename)
if err != nil {
t.Errorf("%s: %v", it.filename, err)
continue loop
}
- b := golden.Bounds()
+ b := g.Bounds()
if !b.Eq(m.Bounds()) {
t.Errorf("%s: want bounds %v got %v", it.filename, b, m.Bounds())
continue loop
}
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
- if !withinTolerance(golden.At(x, y), m.At(x, y), it.tolerance) {
- t.Errorf("%s: at (%d, %d), want %v got %v", it.filename, x, y, golden.At(x, y), m.At(x, y))
+ if !withinTolerance(g.At(x, y), m.At(x, y), it.tolerance) {
+ t.Errorf("%s: at (%d, %d), want %v got %v", it.filename, x, y, g.At(x, y), m.At(x, y))
continue loop
}
}
}
+ if imageFormat == "gif" {
+ // Each frame of a GIF can have a frame-local palette override the
+ // GIF-global palette. Thus, image.Decode can yield a different ColorModel
+ // than image.DecodeConfig.
+ continue
+ }
+ c, _, err := decodeConfig(it.filename)
+ if m.ColorModel() != c.ColorModel {
+ t.Errorf("%s: color models differ", it.filename)
+ continue loop
+ }
}
}
diff --git a/libgo/go/image/draw/bench_test.go b/libgo/go/image/draw/bench_test.go
new file mode 100644
index 00000000000..a99b408141e
--- /dev/null
+++ b/libgo/go/image/draw/bench_test.go
@@ -0,0 +1,206 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+ "image"
+ "image/ycbcr"
+ "testing"
+)
+
+const (
+ dstw, dsth = 640, 480
+ srcw, srch = 400, 300
+)
+
+// bench benchmarks drawing src and mask images onto a dst image with the
+// given op and the color models to create those images from.
+// The created images' pixels are initialized to non-zero values.
+func bench(b *testing.B, dcm, scm, mcm image.ColorModel, op Op) {
+ b.StopTimer()
+
+ var dst Image
+ switch dcm {
+ case image.RGBAColorModel:
+ dst1 := image.NewRGBA(dstw, dsth)
+ for y := 0; y < dsth; y++ {
+ for x := 0; x < dstw; x++ {
+ dst1.SetRGBA(x, y, image.RGBAColor{
+ uint8(5 * x % 0x100),
+ uint8(7 * y % 0x100),
+ uint8((7*x + 5*y) % 0x100),
+ 0xff,
+ })
+ }
+ }
+ dst = dst1
+ case image.RGBA64ColorModel:
+ dst1 := image.NewRGBA64(dstw, dsth)
+ for y := 0; y < dsth; y++ {
+ for x := 0; x < dstw; x++ {
+ dst1.SetRGBA64(x, y, image.RGBA64Color{
+ uint16(53 * x % 0x10000),
+ uint16(59 * y % 0x10000),
+ uint16((59*x + 53*y) % 0x10000),
+ 0xffff,
+ })
+ }
+ }
+ dst = dst1
+ default:
+ panic("unreachable")
+ }
+
+ var src image.Image
+ switch scm {
+ case nil:
+ src = &image.ColorImage{image.RGBAColor{0x11, 0x22, 0x33, 0xff}}
+ case image.RGBAColorModel:
+ src1 := image.NewRGBA(srcw, srch)
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ src1.SetRGBA(x, y, image.RGBAColor{
+ uint8(13 * x % 0x80),
+ uint8(11 * y % 0x80),
+ uint8((11*x + 13*y) % 0x80),
+ 0x7f,
+ })
+ }
+ }
+ src = src1
+ case image.RGBA64ColorModel:
+ src1 := image.NewRGBA64(srcw, srch)
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ src1.SetRGBA64(x, y, image.RGBA64Color{
+ uint16(103 * x % 0x8000),
+ uint16(101 * y % 0x8000),
+ uint16((101*x + 103*y) % 0x8000),
+ 0x7fff,
+ })
+ }
+ }
+ src = src1
+ case image.NRGBAColorModel:
+ src1 := image.NewNRGBA(srcw, srch)
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ src1.SetNRGBA(x, y, image.NRGBAColor{
+ uint8(13 * x % 0x100),
+ uint8(11 * y % 0x100),
+ uint8((11*x + 13*y) % 0x100),
+ 0x7f,
+ })
+ }
+ }
+ src = src1
+ case ycbcr.YCbCrColorModel:
+ yy := make([]uint8, srcw*srch)
+ cb := make([]uint8, srcw*srch)
+ cr := make([]uint8, srcw*srch)
+ for i := range yy {
+ yy[i] = uint8(3 * i % 0x100)
+ cb[i] = uint8(5 * i % 0x100)
+ cr[i] = uint8(7 * i % 0x100)
+ }
+ src = &ycbcr.YCbCr{
+ Y: yy,
+ Cb: cb,
+ Cr: cr,
+ YStride: srcw,
+ CStride: srcw,
+ SubsampleRatio: ycbcr.SubsampleRatio444,
+ Rect: image.Rect(0, 0, srcw, srch),
+ }
+ default:
+ panic("unreachable")
+ }
+
+ var mask image.Image
+ switch mcm {
+ case nil:
+ // No-op.
+ case image.AlphaColorModel:
+ mask1 := image.NewAlpha(srcw, srch)
+ for y := 0; y < srch; y++ {
+ for x := 0; x < srcw; x++ {
+ a := uint8((23*x + 29*y) % 0x100)
+ // Glyph masks are typically mostly zero,
+ // so we only set a quarter of mask1's pixels.
+ if a >= 0xc0 {
+ mask1.SetAlpha(x, y, image.AlphaColor{a})
+ }
+ }
+ }
+ mask = mask1
+ default:
+ panic("unreachable")
+ }
+
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ // Scatter the destination rectangle to draw into.
+ x := 3 * i % (dstw - srcw)
+ y := 7 * i % (dsth - srch)
+
+ DrawMask(dst, dst.Bounds().Add(image.Point{x, y}), src, image.ZP, mask, image.ZP, op)
+ }
+}
+
+// The BenchmarkFoo functions exercise a drawFoo fast-path function in draw.go.
+
+func BenchmarkFillOver(b *testing.B) {
+ bench(b, image.RGBAColorModel, nil, nil, Over)
+}
+
+func BenchmarkFillSrc(b *testing.B) {
+ bench(b, image.RGBAColorModel, nil, nil, Src)
+}
+
+func BenchmarkCopyOver(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.RGBAColorModel, nil, Over)
+}
+
+func BenchmarkCopySrc(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.RGBAColorModel, nil, Src)
+}
+
+func BenchmarkNRGBAOver(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.NRGBAColorModel, nil, Over)
+}
+
+func BenchmarkNRGBASrc(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.NRGBAColorModel, nil, Src)
+}
+
+func BenchmarkYCbCr(b *testing.B) {
+ bench(b, image.RGBAColorModel, ycbcr.YCbCrColorModel, nil, Over)
+}
+
+func BenchmarkGlyphOver(b *testing.B) {
+ bench(b, image.RGBAColorModel, nil, image.AlphaColorModel, Over)
+}
+
+func BenchmarkRGBA(b *testing.B) {
+ bench(b, image.RGBAColorModel, image.RGBA64ColorModel, nil, Src)
+}
+
+// The BenchmarkGenericFoo functions exercise the generic, slow-path code.
+
+func BenchmarkGenericOver(b *testing.B) {
+ bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, nil, Over)
+}
+
+func BenchmarkGenericMaskOver(b *testing.B) {
+ bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, image.AlphaColorModel, Over)
+}
+
+func BenchmarkGenericSrc(b *testing.B) {
+ bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, nil, Src)
+}
+
+func BenchmarkGenericMaskSrc(b *testing.B) {
+ bench(b, image.RGBA64ColorModel, image.RGBA64ColorModel, image.AlphaColorModel, Src)
+}
diff --git a/libgo/go/image/draw/clip_test.go b/libgo/go/image/draw/clip_test.go
new file mode 100644
index 00000000000..db40d82f546
--- /dev/null
+++ b/libgo/go/image/draw/clip_test.go
@@ -0,0 +1,193 @@
+// 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 draw
+
+import (
+ "image"
+ "testing"
+)
+
+type clipTest struct {
+ desc string
+ r, dr, sr, mr image.Rectangle
+ sp, mp image.Point
+ nilMask bool
+ r0 image.Rectangle
+ sp0, mp0 image.Point
+}
+
+var clipTests = []clipTest{
+ // The following tests all have a nil mask.
+ {
+ "basic",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(0, 0, 100, 100),
+ image.ZP,
+ image.ZP,
+ },
+ {
+ "clip dr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(40, 40, 60, 60),
+ image.Rect(0, 0, 100, 100),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(40, 40, 60, 60),
+ image.Pt(40, 40),
+ image.ZP,
+ },
+ {
+ "clip sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 100, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(20, 20, 80, 80),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.ZP,
+ image.ZP,
+ true,
+ image.Rect(20, 20, 50, 80),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (top-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 8),
+ image.ZP,
+ true,
+ image.Rect(5, 12, 50, 72),
+ image.Pt(20, 20),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (middle-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 66),
+ image.ZP,
+ true,
+ image.Rect(5, 0, 50, 14),
+ image.Pt(20, 66),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp outside sr (bottom-left)",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(15, 91),
+ image.ZP,
+ true,
+ image.ZR,
+ image.Pt(15, 91),
+ image.ZP,
+ },
+ {
+ "clip dr and sr, sp inside sr",
+ image.Rect(0, 0, 100, 100),
+ image.Rect(0, 0, 50, 100),
+ image.Rect(20, 20, 80, 80),
+ image.ZR,
+ image.Pt(44, 33),
+ image.ZP,
+ true,
+ image.Rect(0, 0, 36, 47),
+ image.Pt(44, 33),
+ image.ZP,
+ },
+
+ // The following tests all have a non-nil mask.
+ {
+ "basic mask",
+ image.Rect(0, 0, 80, 80),
+ image.Rect(20, 0, 100, 80),
+ image.Rect(0, 0, 50, 49),
+ image.Rect(0, 0, 46, 47),
+ image.ZP,
+ image.ZP,
+ false,
+ image.Rect(20, 0, 46, 47),
+ image.Pt(20, 0),
+ image.Pt(20, 0),
+ },
+ // TODO(nigeltao): write more tests.
+}
+
+func TestClip(t *testing.T) {
+ dst0 := image.NewRGBA(100, 100)
+ src0 := image.NewRGBA(100, 100)
+ mask0 := image.NewRGBA(100, 100)
+ for _, c := range clipTests {
+ dst := dst0.SubImage(c.dr).(*image.RGBA)
+ src := src0.SubImage(c.sr).(*image.RGBA)
+ var mask image.Image
+ if !c.nilMask {
+ mask = mask0.SubImage(c.mr)
+ }
+ r, sp, mp := c.r, c.sp, c.mp
+ clip(dst, &r, src, &sp, mask, &mp)
+
+ // Check that the actual results equal the expected results.
+ if !c.r0.Eq(r) {
+ t.Errorf("%s: clip rectangle want %v got %v", c.desc, c.r0, r)
+ continue
+ }
+ if !c.sp0.Eq(sp) {
+ t.Errorf("%s: sp want %v got %v", c.desc, c.sp0, sp)
+ continue
+ }
+ if !c.nilMask {
+ if !c.mp0.Eq(mp) {
+ t.Errorf("%s: mp want %v got %v", c.desc, c.mp0, mp)
+ continue
+ }
+ }
+
+ // Check that the clipped rectangle is contained by the dst / src / mask
+ // rectangles, in their respective co-ordinate spaces.
+ if !r.In(c.dr) {
+ t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r)
+ }
+ // sr is r translated into src's co-ordinate space.
+ sr := r.Add(c.sp.Sub(c.dr.Min))
+ if !sr.In(c.sr) {
+ t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr)
+ }
+ if !c.nilMask {
+ // mr is r translated into mask's co-ordinate space.
+ mr := r.Add(c.mp.Sub(c.dr.Min))
+ if !mr.In(c.mr) {
+ t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr)
+ }
+ }
+ }
+}
diff --git a/libgo/go/exp/draw/draw.go b/libgo/go/image/draw/draw.go
index f98e2461894..a748ff8c77a 100644
--- a/libgo/go/exp/draw/draw.go
+++ b/libgo/go/image/draw/draw.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package draw provides basic graphics and drawing primitives,
+// Package draw provides image composition functions
// in the style of the Plan 9 graphics library
// (see http://plan9.bell-labs.com/magic/man2html/2/draw)
// and the X Render extension.
@@ -16,7 +16,7 @@ import (
// m is the maximum color value returned by image.Color.RGBA.
const m = 1<<16 - 1
-// A Porter-Duff compositing operator.
+// Op is a Porter-Duff compositing operator.
type Op int
const (
@@ -34,32 +34,36 @@ type Image interface {
Set(x, y int, c image.Color)
}
-// Draw calls DrawMask with a nil mask and an Over op.
-func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
- DrawMask(dst, r, src, sp, nil, image.ZP, Over)
+// Draw calls DrawMask with a nil mask.
+func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
+ DrawMask(dst, r, src, sp, nil, image.ZP, op)
}
-// 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
+// clip clips r against each image's bounds (after translating into the
+// destination image's co-ordinate space) and shifts the points sp and mp by
+// the same amount as the change in r.Min.
+func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
+ orig := r.Min
+ *r = r.Intersect(dst.Bounds())
+ *r = r.Intersect(src.Bounds().Add(orig.Sub(*sp)))
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
+ *r = r.Intersect(mask.Bounds().Add(orig.Sub(*mp)))
}
- if r.Dy() > dy {
- r.Max.Y = r.Min.Y + dy
+ dx := r.Min.X - orig.X
+ dy := r.Min.Y - orig.Y
+ if dx == 0 && dy == 0 {
+ return
}
- r = r.Intersect(dst.Bounds())
+ (*sp).X += dx
+ (*sp).Y += dy
+ (*mp).X += dx
+ (*mp).Y += dy
+}
+
+// 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) {
+ clip(dst, &r, src, &sp, mask, &mp)
if r.Empty() {
return
}
@@ -166,33 +170,53 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
}
func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
- cr, cg, cb, ca := src.RGBA()
+ sr, sg, sb, sa := 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)}
+ a := (m - sa) * 0x101
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
+ for y := r.Min.Y; y != r.Max.Y; y++ {
+ for i := i0; i < i1; i += 4 {
+ dr := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
+ dst.Pix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dst.Pix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dst.Pix[i+2] = uint8((db*a/m + sb) >> 8)
+ dst.Pix[i+3] = uint8((da*a/m + sa) >> 8)
}
+ i0 += dst.Stride
+ i1 += dst.Stride
+ }
+}
+
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
+ sr, sg, sb, sa := src.RGBA()
+ // The built-in copy function is faster than a straightforward for loop to fill the destination with
+ // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
+ // then use the first row as the slice source for the remaining rows.
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
+ for i := i0; i < i1; i += 4 {
+ dst.Pix[i+0] = uint8(sr >> 8)
+ dst.Pix[i+1] = uint8(sg >> 8)
+ dst.Pix[i+2] = uint8(sb >> 8)
+ dst.Pix[i+3] = uint8(sa >> 8)
+ }
+ firstRow := dst.Pix[i0:i1]
+ for y := r.Min.Y + 1; y < r.Max.Y; y++ {
+ i0 += dst.Stride
+ i1 += dst.Stride
+ copy(dst.Pix[i0:i1], firstRow)
}
}
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
+ dx, dy := r.Dx(), r.Dy()
+ d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
var (
ddelta, sdelta int
i0, i1, idelta int
@@ -200,139 +224,47 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
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
+ i0, i1, idelta = 0, dx*4, +4
} 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
+ d0 += (dy - 1) * dst.Stride
+ s0 += (dy - 1) * src.Stride
ddelta = -dst.Stride
sdelta = -src.Stride
- i0, i1, idelta = d1-d0-1, -1, -1
+ i0, i1, idelta = (dx-1)*4, -4, -4
}
- for ; nrows > 0; nrows-- {
- dpix := dst.Pix[d0:d1]
- spix := src.Pix[s0:s1]
+ for ; dy > 0; dy-- {
+ dpix := dst.Pix[d0:]
+ spix := src.Pix[s0:]
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)
+ sr := uint32(spix[i+0]) * 0x101
+ sg := uint32(spix[i+1]) * 0x101
+ sb := uint32(spix[i+2]) * 0x101
+ sa := uint32(spix[i+3]) * 0x101
+
+ dr := uint32(dpix[i+0])
+ dg := uint32(dpix[i+1])
+ db := uint32(dpix[i+2])
+ da := uint32(dpix[i+3])
+
// 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)}
+
+ dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dpix[i+2] = uint8((db*a/m + sb) >> 8)
+ dpix[i+3] = uint8((da*a/m + sa) >> 8)
}
d0 += ddelta
- d1 += ddelta
s0 += sdelta
- s1 += sdelta
- }
-}
-
-func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
- for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
- spix := src.Pix[sy*src.Stride : (sy+1)*src.Stride]
- for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
- // Convert from non-premultiplied color to pre-multiplied color.
- // The order of operations here is to match the NRGBAColor.RGBA
- // method in image/color.go.
- snrgba := spix[sx]
- sa := uint32(snrgba.A)
- sr := uint32(snrgba.R) * 0x101 * sa / 0xff
- sg := uint32(snrgba.G) * 0x101 * sa / 0xff
- sb := uint32(snrgba.B) * 0x101 * sa / 0xff
- sa *= 0x101
-
- rgba := dpix[x]
- dr := uint32(rgba.R)
- dg := uint32(rgba.G)
- db := uint32(rgba.B)
- da := uint32(rgba.A)
- a := (m - sa) * 0x101
- dr = (dr*a + sr*m) / m
- dg = (dg*a + sg*m) / m
- db = (db*a + sb*m) / m
- da = (da*a + sa*m) / m
- dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
- }
- }
-}
-
-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
+ n, dy := 4*r.Dx(), r.Dy()
+ d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4
var ddelta, sdelta int
if r.Min.Y <= sp.Y {
ddelta = dst.Stride
@@ -341,38 +273,76 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P
// 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
+ d0 += (dy - 1) * dst.Stride
+ s0 += (dy - 1) * src.Stride
ddelta = -dst.Stride
sdelta = -src.Stride
}
- for ; nrows > 0; nrows-- {
- copy(dst.Pix[d0:d1], src.Pix[s0:s1])
+ for ; dy > 0; dy-- {
+ copy(dst.Pix[d0:d0+n], src.Pix[s0:s0+n])
d0 += ddelta
- d1 += ddelta
s0 += sdelta
- s1 += sdelta
+ }
+}
+
+func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
+ i0 := (r.Min.X - dst.Rect.Min.X) * 4
+ i1 := (r.Max.X - dst.Rect.Min.X) * 4
+ si0 := (sp.X - src.Rect.Min.X) * 4
+ yMax := r.Max.Y - dst.Rect.Min.Y
+
+ y := r.Min.Y - dst.Rect.Min.Y
+ sy := sp.Y - src.Rect.Min.Y
+ for ; y != yMax; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ spix := src.Pix[sy*src.Stride:]
+
+ for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
+ // Convert from non-premultiplied color to pre-multiplied color.
+ sa := uint32(spix[si+3]) * 0x101
+ sr := uint32(spix[si+0]) * sa / 0xff
+ sg := uint32(spix[si+1]) * sa / 0xff
+ sb := uint32(spix[si+2]) * sa / 0xff
+
+ dr := uint32(dpix[i+0])
+ dg := uint32(dpix[i+1])
+ db := uint32(dpix[i+2])
+ da := uint32(dpix[i+3])
+
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - sa) * 0x101
+
+ dpix[i+0] = uint8((dr*a/m + sr) >> 8)
+ dpix[i+1] = uint8((dg*a/m + sg) >> 8)
+ dpix[i+2] = uint8((db*a/m + sb) >> 8)
+ dpix[i+3] = uint8((da*a/m + sa) >> 8)
+ }
}
}
func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) {
- for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
- spix := src.Pix[sy*src.Stride : (sy+1)*src.Stride]
- for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+ i0 := (r.Min.X - dst.Rect.Min.X) * 4
+ i1 := (r.Max.X - dst.Rect.Min.X) * 4
+ si0 := (sp.X - src.Rect.Min.X) * 4
+ yMax := r.Max.Y - dst.Rect.Min.Y
+
+ y := r.Min.Y - dst.Rect.Min.Y
+ sy := sp.Y - src.Rect.Min.Y
+ for ; y != yMax; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ spix := src.Pix[sy*src.Stride:]
+
+ for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
// Convert from non-premultiplied color to pre-multiplied color.
- // The order of operations here is to match the NRGBAColor.RGBA
- // method in image/color.go.
- snrgba := spix[sx]
- sa := uint32(snrgba.A)
- sr := uint32(snrgba.R) * 0x101 * sa / 0xff
- sg := uint32(snrgba.G) * 0x101 * sa / 0xff
- sb := uint32(snrgba.B) * 0x101 * sa / 0xff
- sa *= 0x101
-
- dpix[x] = image.RGBAColor{uint8(sr >> 8), uint8(sg >> 8), uint8(sb >> 8), uint8(sa >> 8)}
+ sa := uint32(spix[si+3]) * 0x101
+ sr := uint32(spix[si+0]) * sa / 0xff
+ sg := uint32(spix[si+1]) * sa / 0xff
+ sb := uint32(spix[si+2]) * sa / 0xff
+
+ dpix[i+0] = uint8(sr >> 8)
+ dpix[i+1] = uint8(sg >> 8)
+ dpix[i+2] = uint8(sb >> 8)
+ dpix[i+3] = uint8(sa >> 8)
}
}
}
@@ -382,45 +352,89 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
// (i.e. fully opaque) then the op is effectively always Src.
var (
yy, cb, cr uint8
- rr, gg, bb uint8
)
+ x0 := (r.Min.X - dst.Rect.Min.X) * 4
+ x1 := (r.Max.X - dst.Rect.Min.X) * 4
+ y0 := r.Min.Y - dst.Rect.Min.Y
+ y1 := r.Max.Y - dst.Rect.Min.Y
switch src.SubsampleRatio {
case ycbcr.SubsampleRatio422:
- for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
- for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
i := sx / 2
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[sy*src.CStride+i]
cr = src.Cr[sy*src.CStride+i]
- rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
- dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
}
}
case ycbcr.SubsampleRatio420:
- for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
- for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
i, j := sx/2, sy/2
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[j*src.CStride+i]
cr = src.Cr[j*src.CStride+i]
- rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
- dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
}
}
default:
// Default to 4:4:4 subsampling.
- for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 {
- dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
- for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 {
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
yy = src.Y[sy*src.YStride+sx]
cb = src.Cb[sy*src.CStride+sx]
cr = src.Cr[sy*src.CStride+sx]
- rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr)
- dpix[x] = image.RGBAColor{rr, gg, bb, 255}
+ rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
+ }
+ }
+ }
+}
+
+func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
+ i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4
+ i1 := i0 + r.Dx()*4
+ mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X
+ sr, sg, sb, sa := src.RGBA()
+ for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 {
+ for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 {
+ ma := uint32(mask.Pix[mi])
+ if ma == 0 {
+ continue
}
+ ma |= ma << 8
+
+ dr := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
+ // The 0x101 is here for the same reason as in drawRGBA.
+ a := (m - (sa * ma / m)) * 0x101
+
+ dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+ dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+ dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+ dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
}
+ i0 += dst.Stride
+ i1 += dst.Stride
+ mi0 += mask.Stride
}
}
@@ -436,23 +450,24 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
sy := sp.Y + y0 - r.Min.Y
my := mp.Y + y0 - r.Min.Y
+ sx0 := sp.X + x0 - r.Min.X
+ mx0 := mp.X + x0 - r.Min.X
+ sx1 := sx0 + (x1 - x0)
+ i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4
+ di := dx * 4
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 {
+ for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, 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 := uint32(dst.Pix[i+0])
+ dg := uint32(dst.Pix[i+1])
+ db := uint32(dst.Pix[i+2])
+ da := uint32(dst.Pix[i+3])
+
// 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
@@ -460,17 +475,19 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
// (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
+
+ dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
+ dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
+ dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
+ dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
+
} else {
- dr = sr * ma / m
- dg = sg * ma / m
- db = sb * ma / m
- da = sa * ma / m
+ dst.Pix[i+0] = uint8(sr * ma / m >> 8)
+ dst.Pix[i+1] = uint8(sg * ma / m >> 8)
+ dst.Pix[i+2] = uint8(sb * ma / m >> 8)
+ dst.Pix[i+3] = uint8(sa * ma / m >> 8)
}
- dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
}
+ i0 += dy * dst.Stride
}
}
diff --git a/libgo/go/exp/draw/draw_test.go b/libgo/go/image/draw/draw_test.go
index 873a2f24a40..55435cc2719 100644
--- a/libgo/go/exp/draw/draw_test.go
+++ b/libgo/go/image/draw/draw_test.go
@@ -154,22 +154,32 @@ var drawTests = []drawTest{
{"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
}
-func makeGolden(dst, src, mask image.Image, op Op) image.Image {
+func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, 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
+ sb := src.Bounds()
+ mb := image.Rect(-1e9, -1e9, 1e9, 1e9)
if mask != nil {
- mx0 = mask.Bounds().Min.X - b.Min.X
- my0 = mask.Bounds().Min.Y - b.Min.Y
+ mb = mask.Bounds()
}
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
+ for y := r.Min.Y; y < r.Max.Y; y++ {
+ sy := y + sp.Y - r.Min.Y
+ my := y + mp.Y - r.Min.Y
+ for x := r.Min.X; x < r.Max.X; x++ {
+ if !(image.Point{x, y}.In(b)) {
+ continue
+ }
+ sx := x + sp.X - r.Min.X
+ if !(image.Point{sx, sy}.In(sb)) {
+ continue
+ }
+ mx := x + mp.X - r.Min.X
+ if !(image.Point{mx, my}.In(mb)) {
+ continue
+ }
+
const M = 1<<16 - 1
var dr, dg, db, da uint32
if op == Over {
@@ -189,35 +199,49 @@ func makeGolden(dst, src, mask image.Image, op Op) image.Image {
})
}
}
- golden.Rect = b
- return golden
+ return golden.SubImage(b)
}
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
+ rr := []image.Rectangle{
+ image.Rect(0, 0, 0, 0),
+ image.Rect(0, 0, 16, 16),
+ image.Rect(3, 5, 12, 10),
+ image.Rect(0, 0, 9, 9),
+ image.Rect(8, 8, 16, 16),
+ image.Rect(8, 0, 9, 16),
+ image.Rect(0, 8, 16, 9),
+ image.Rect(8, 8, 9, 9),
+ image.Rect(8, 8, 8, 8),
+ }
+ for _, r := range rr {
+ loop:
+ for _, test := range drawTests {
+ dst := hgradRed(255).(*image.RGBA).SubImage(r).(Image)
+ // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+ golden := makeGolden(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
+ b := dst.Bounds()
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("draw %v %s: bounds %v versus %v", r, test.desc, dst.Bounds(), golden.Bounds())
+ continue
+ }
+ // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+ DrawMask(dst, image.Rect(0, 0, 16, 16), test.src, image.ZP, test.mask, image.ZP, test.op)
+ if image.Pt(8, 8).In(r) {
+ // 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 %v %s: at (8, 8) %v versus %v", r, 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 %v %s: at (%d, %d), %v versus golden %v", r, test.desc, x, y, dst.At(x, y), golden.At(x, y))
+ continue loop
+ }
}
}
}
@@ -230,19 +254,11 @@ func TestDrawOverlap(t *testing.T) {
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)
+ dst := m.SubImage(image.Rect(5, 5, 10, 10)).(*image.RGBA)
+ src := m.SubImage(image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff)).(*image.RGBA)
b := dst.Bounds()
+ // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+ golden := makeGolden(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
if !b.Eq(golden.Bounds()) {
t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
continue
@@ -263,16 +279,76 @@ func TestDrawOverlap(t *testing.T) {
}
}
-// TestIssue836 verifies http://code.google.com/p/go/issues/detail?id=836.
-func TestIssue836(t *testing.T) {
+// TestNonZeroSrcPt checks drawing with a non-zero src point parameter.
+func TestNonZeroSrcPt(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))
+ Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1), Over)
if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
- t.Errorf("Issue 836: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
+ t.Errorf("non-zero src pt: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
+ }
+}
+
+func TestFill(t *testing.T) {
+ rr := []image.Rectangle{
+ image.Rect(0, 0, 0, 0),
+ image.Rect(0, 0, 40, 30),
+ image.Rect(10, 0, 40, 30),
+ image.Rect(0, 20, 40, 30),
+ image.Rect(10, 20, 40, 30),
+ image.Rect(10, 20, 15, 25),
+ image.Rect(10, 0, 35, 30),
+ image.Rect(0, 15, 40, 16),
+ image.Rect(24, 24, 25, 25),
+ image.Rect(23, 23, 26, 26),
+ image.Rect(22, 22, 27, 27),
+ image.Rect(21, 21, 28, 28),
+ image.Rect(20, 20, 29, 29),
+ }
+ for _, r := range rr {
+ m := image.NewRGBA(40, 30).SubImage(r).(*image.RGBA)
+ b := m.Bounds()
+ c := image.RGBAColor{11, 0, 0, 255}
+ src := &image.ColorImage{c}
+ check := func(desc string) {
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if !eq(c, m.At(x, y)) {
+ t.Errorf("%s fill: at (%d, %d), sub-image bounds=%v: want %v got %v", desc, x, y, r, c, m.At(x, y))
+ return
+ }
+ }
+ }
+ }
+ // Draw 1 pixel at a time.
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ DrawMask(m, image.Rect(x, y, x+1, y+1), src, image.ZP, nil, image.ZP, Src)
+ }
+ }
+ check("pixel")
+ // Draw 1 row at a time.
+ c = image.RGBAColor{0, 22, 0, 255}
+ src = &image.ColorImage{c}
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ DrawMask(m, image.Rect(b.Min.X, y, b.Max.X, y+1), src, image.ZP, nil, image.ZP, Src)
+ }
+ check("row")
+ // Draw 1 column at a time.
+ c = image.RGBAColor{0, 0, 33, 255}
+ src = &image.ColorImage{c}
+ for x := b.Min.X; x < b.Max.X; x++ {
+ DrawMask(m, image.Rect(x, b.Min.Y, x+1, b.Max.Y), src, image.ZP, nil, image.ZP, Src)
+ }
+ check("column")
+ // Draw the whole image at once.
+ c = image.RGBAColor{44, 55, 66, 77}
+ src = &image.ColorImage{c}
+ DrawMask(m, b, src, image.ZP, nil, image.ZP, Src)
+ check("whole")
}
}
diff --git a/libgo/go/image/geom.go b/libgo/go/image/geom.go
index ccfe9cdb082..667aee6259e 100644
--- a/libgo/go/image/geom.go
+++ b/libgo/go/image/geom.go
@@ -38,6 +38,12 @@ func (p Point) Div(k int) Point {
return Point{p.X / k, p.Y / k}
}
+// In returns whether p is in r.
+func (p Point) In(r Rectangle) bool {
+ return r.Min.X <= p.X && p.X < r.Max.X &&
+ r.Min.Y <= p.Y && p.Y < r.Max.Y
+}
+
// 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 {
@@ -190,10 +196,15 @@ func (r Rectangle) Overlaps(s Rectangle) bool {
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
+// In returns whether every point in r is in s.
+func (r Rectangle) In(s Rectangle) bool {
+ if r.Empty() {
+ return true
+ }
+ // Note that r.Max is an exclusive bound for r, so that r.In(s)
+ // does not require that r.Max.In(s).
+ return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
+ s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
}
// Canon returns the canonical version of r. The returned rectangle has minimum
diff --git a/libgo/go/image/gif/reader.go b/libgo/go/image/gif/reader.go
index d37f52689ee..e39b7974604 100644
--- a/libgo/go/image/gif/reader.go
+++ b/libgo/go/image/gif/reader.go
@@ -28,7 +28,9 @@ const (
fColorMapFollows = 1 << 7
// Image fields.
- ifInterlace = 1 << 6
+ ifLocalColorTable = 1 << 7
+ ifInterlace = 1 << 6
+ ifPixelSizeMask = 7
// Graphic control flags.
gcTransparentColorSet = 1 << 0
@@ -94,28 +96,26 @@ type blockReader struct {
tmp [256]byte
}
-func (b *blockReader) Read(p []byte) (n int, err os.Error) {
+func (b *blockReader) Read(p []byte) (int, os.Error) {
if len(p) == 0 {
- return
+ return 0, nil
}
- if len(b.slice) > 0 {
- n = copy(p, b.slice)
- b.slice = b.slice[n:]
- return
- }
- var blockLen uint8
- blockLen, err = b.r.ReadByte()
- if err != nil {
- return
- }
- if blockLen == 0 {
- return 0, os.EOF
- }
- b.slice = b.tmp[0:blockLen]
- if _, err = io.ReadFull(b.r, b.slice); err != nil {
- return
+ if len(b.slice) == 0 {
+ blockLen, err := b.r.ReadByte()
+ if err != nil {
+ return 0, err
+ }
+ if blockLen == 0 {
+ return 0, os.EOF
+ }
+ b.slice = b.tmp[0:blockLen]
+ if _, err = io.ReadFull(b.r, b.slice); err != nil {
+ return 0, err
+ }
}
- return b.Read(p)
+ n := copy(p, b.slice)
+ b.slice = b.slice[n:]
+ return n, nil
}
// decode reads a GIF image from r and stores the result in d.
@@ -141,8 +141,6 @@ func (d *decoder) decode(r io.Reader, configOnly bool) os.Error {
}
}
- d.image = nil
-
Loop:
for err == nil {
var c byte
@@ -175,11 +173,10 @@ Loop:
if err != nil {
return err
}
- if litWidth > 8 {
+ if litWidth < 2 || litWidth > 8 {
return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth)
}
- // A wonderfully Go-like piece of magic. Unfortunately it's only at its
- // best for 8-bit pixels.
+ // A wonderfully Go-like piece of magic.
lzwr := lzw.NewReader(&blockReader{r: d.r}, lzw.LSB, int(litWidth))
if _, err = io.ReadFull(lzwr, m.Pix); err != nil {
break
@@ -191,8 +188,14 @@ Loop:
return err
}
if c != 0 {
- return os.ErrorString("gif: extra data after image")
+ return os.NewError("gif: extra data after image")
+ }
+
+ // Undo the interlacing if necessary.
+ if d.imageFields&ifInterlace != 0 {
+ uninterlace(m)
}
+
d.image = append(d.image, m)
d.delay = append(d.delay, d.delayTime)
d.delayTime = 0 // TODO: is this correct, or should we hold on to the value?
@@ -237,6 +240,9 @@ func (d *decoder) readColorMap() (image.PalettedColorModel, os.Error) {
return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize)
}
numColors := 1 << d.pixelSize
+ if d.imageFields&ifLocalColorTable != 0 {
+ numColors = 1 << ((d.imageFields & ifPixelSizeMask) + 1)
+ }
numValues := 3 * numColors
_, err := io.ReadFull(d.r, d.tmp[0:numValues])
if err != nil {
@@ -275,7 +281,7 @@ func (d *decoder) readExtension() os.Error {
return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
}
if size > 0 {
- if _, err := d.r.Read(d.tmp[0:size]); err != nil {
+ if _, err := io.ReadFull(d.r, d.tmp[0:size]); err != nil {
return err
}
}
@@ -323,15 +329,15 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, os.Error) {
if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
}
- _ = int(d.tmp[0]) + int(d.tmp[1])<<8 // TODO: honor left value
- _ = int(d.tmp[2]) + int(d.tmp[3])<<8 // TODO: honor top value
+ left := int(d.tmp[0]) + int(d.tmp[1])<<8
+ top := int(d.tmp[2]) + int(d.tmp[3])<<8
width := int(d.tmp[4]) + int(d.tmp[5])<<8
height := int(d.tmp[6]) + int(d.tmp[7])<<8
d.imageFields = d.tmp[8]
- if d.imageFields&ifInterlace != 0 {
- return nil, os.ErrorString("gif: can't handle interlaced images")
- }
- return image.NewPaletted(width, height, nil), nil
+ m := image.NewPaletted(width, height, nil)
+ // Overwrite the rectangle to take account of left and top.
+ m.Rect = image.Rect(left, top, left+width, top+height)
+ return m, nil
}
func (d *decoder) readBlock() (int, os.Error) {
@@ -342,9 +348,39 @@ func (d *decoder) readBlock() (int, os.Error) {
return io.ReadFull(d.r, d.tmp[0:n])
}
+// interlaceScan defines the ordering for a pass of the interlace algorithm.
+type interlaceScan struct {
+ skip, start int
+}
+
+// interlacing represents the set of scans in an interlaced GIF image.
+var interlacing = []interlaceScan{
+ {8, 0}, // Group 1 : Every 8th. row, starting with row 0.
+ {8, 4}, // Group 2 : Every 8th. row, starting with row 4.
+ {4, 2}, // Group 3 : Every 4th. row, starting with row 2.
+ {2, 1}, // Group 4 : Every 2nd. row, starting with row 1.
+}
+
+// uninterlace rearranges the pixels in m to account for interlaced input.
+func uninterlace(m *image.Paletted) {
+ var nPix []uint8
+ dx := m.Bounds().Dx()
+ dy := m.Bounds().Dy()
+ nPix = make([]uint8, dx*dy)
+ offset := 0 // steps through the input by sequential scan lines.
+ for _, pass := range interlacing {
+ nOffset := pass.start * dx // steps through the output as defined by pass.
+ for y := pass.start; y < dy; y += pass.skip {
+ copy(nPix[nOffset:nOffset+dx], m.Pix[offset:offset+dx])
+ offset += dx
+ nOffset += dx * pass.skip
+ }
+ }
+ m.Pix = nPix
+}
+
// Decode reads a GIF image from r and returns the first embedded
// image as an image.Image.
-// Limitation: The file must be 8 bits per pixel and have no interlacing.
func Decode(r io.Reader) (image.Image, os.Error) {
var d decoder
if err := d.decode(r, false); err != nil {
@@ -362,7 +398,6 @@ type GIF struct {
// DecodeAll reads a GIF image from r and returns the sequential frames
// and timing information.
-// Limitation: The file must be 8 bits per pixel and have no interlacing.
func DecodeAll(r io.Reader) (*GIF, os.Error) {
var d decoder
if err := d.decode(r, false); err != nil {
@@ -376,15 +411,14 @@ func DecodeAll(r io.Reader) (*GIF, os.Error) {
return gif, nil
}
-// DecodeConfig returns the color model and dimensions of a GIF image without
-// decoding the entire image.
+// DecodeConfig returns the global color model and dimensions of a GIF 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
}
- colorMap := d.globalColorMap
- return image.Config{colorMap, d.width, d.height}, nil
+ return image.Config{d.globalColorMap, d.width, d.height}, nil
}
func init() {
diff --git a/libgo/go/image/image.go b/libgo/go/image/image.go
index 4350acc8203..11def94354a 100644
--- a/libgo/go/image/image.go
+++ b/libgo/go/image/image.go
@@ -5,13 +5,13 @@
// Package image implements a basic 2-D image library.
package image
-// A Config consists of an image's color model and dimensions.
+// Config holds 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.
+// Image is a finite rectangular grid of Colors drawn from a ColorModel.
type Image interface {
// ColorModel returns the Image's ColorModel.
ColorModel() ColorModel
@@ -24,10 +24,12 @@ type Image interface {
At(x, y int) Color
}
-// An RGBA is an in-memory image of RGBAColor values.
+// 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
+ // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -38,24 +40,52 @@ 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}) {
+ if !(Point{x, y}.In(p.Rect)) {
return RGBAColor{}
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ return RGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
}
func (p *RGBA) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ c1 := toRGBAColor(c).(RGBAColor)
+ p.Pix[i+0] = c1.R
+ p.Pix[i+1] = c1.G
+ p.Pix[i+2] = c1.B
+ p.Pix[i+3] = c1.A
}
func (p *RGBA) SetRGBA(x, y int, c RGBAColor) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ p.Pix[i+0] = c.R
+ p.Pix[i+1] = c.G
+ p.Pix[i+2] = c.B
+ p.Pix[i+3] = c.A
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *RGBA) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &RGBA{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
+ return &RGBA{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -63,11 +93,10 @@ 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
+ i0, i1 := 3, p.Rect.Dx()*4
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xff {
+ for i := i0; i < i1; i += 4 {
+ if p.Pix[i] != 0xff {
return false
}
}
@@ -79,14 +108,16 @@ func (p *RGBA) Opaque() bool {
// 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}}}
+ buf := make([]uint8, 4*w*h)
+ return &RGBA{buf, 4 * w, Rectangle{ZP, Point{w, h}}}
}
-// An RGBA64 is an in-memory image of RGBA64Color values.
+// 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
+ // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -97,24 +128,65 @@ 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}) {
+ if !(Point{x, y}.In(p.Rect)) {
return RGBA64Color{}
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ return RGBA64Color{
+ uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+ uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+ uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+ uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+ }
}
func (p *RGBA64) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ c1 := toRGBA64Color(c).(RGBA64Color)
+ p.Pix[i+0] = uint8(c1.R >> 8)
+ p.Pix[i+1] = uint8(c1.R)
+ p.Pix[i+2] = uint8(c1.G >> 8)
+ p.Pix[i+3] = uint8(c1.G)
+ p.Pix[i+4] = uint8(c1.B >> 8)
+ p.Pix[i+5] = uint8(c1.B)
+ p.Pix[i+6] = uint8(c1.A >> 8)
+ p.Pix[i+7] = uint8(c1.A)
}
func (p *RGBA64) SetRGBA64(x, y int, c RGBA64Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ p.Pix[i+0] = uint8(c.R >> 8)
+ p.Pix[i+1] = uint8(c.R)
+ p.Pix[i+2] = uint8(c.G >> 8)
+ p.Pix[i+3] = uint8(c.G)
+ p.Pix[i+4] = uint8(c.B >> 8)
+ p.Pix[i+5] = uint8(c.B)
+ p.Pix[i+6] = uint8(c.A >> 8)
+ p.Pix[i+7] = uint8(c.A)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *RGBA64) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &RGBA64{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
+ return &RGBA64{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -122,11 +194,10 @@ 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
+ i0, i1 := 6, p.Rect.Dx()*8
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xffff {
+ for i := i0; i < i1; i += 8 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
return false
}
}
@@ -138,14 +209,16 @@ func (p *RGBA64) Opaque() bool {
// 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}}}
+ pix := make([]uint8, 8*w*h)
+ return &RGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
}
-// An NRGBA is an in-memory image of NRGBAColor values.
+// 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
+ // Pix holds the image's pixels, in R, G, B, A order. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -156,24 +229,52 @@ 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}) {
+ if !(Point{x, y}.In(p.Rect)) {
return NRGBAColor{}
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ return NRGBAColor{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
}
func (p *NRGBA) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ c1 := toNRGBAColor(c).(NRGBAColor)
+ p.Pix[i+0] = c1.R
+ p.Pix[i+1] = c1.G
+ p.Pix[i+2] = c1.B
+ p.Pix[i+3] = c1.A
}
func (p *NRGBA) SetNRGBA(x, y int, c NRGBAColor) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+ p.Pix[i+0] = c.R
+ p.Pix[i+1] = c.G
+ p.Pix[i+2] = c.B
+ p.Pix[i+3] = c.A
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *NRGBA) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &NRGBA{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4
+ return &NRGBA{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -181,11 +282,10 @@ 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
+ i0, i1 := 3, p.Rect.Dx()*4
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xff {
+ for i := i0; i < i1; i += 4 {
+ if p.Pix[i] != 0xff {
return false
}
}
@@ -197,14 +297,16 @@ func (p *NRGBA) Opaque() bool {
// 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}}}
+ pix := make([]uint8, 4*w*h)
+ return &NRGBA{pix, 4 * w, Rectangle{ZP, Point{w, h}}}
}
-// An NRGBA64 is an in-memory image of NRGBA64Color values.
+// 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
+ // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -215,24 +317,65 @@ 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}) {
+ if !(Point{x, y}.In(p.Rect)) {
return NRGBA64Color{}
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ return NRGBA64Color{
+ uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
+ uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
+ uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
+ uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
+ }
}
func (p *NRGBA64) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ c1 := toNRGBA64Color(c).(NRGBA64Color)
+ p.Pix[i+0] = uint8(c1.R >> 8)
+ p.Pix[i+1] = uint8(c1.R)
+ p.Pix[i+2] = uint8(c1.G >> 8)
+ p.Pix[i+3] = uint8(c1.G)
+ p.Pix[i+4] = uint8(c1.B >> 8)
+ p.Pix[i+5] = uint8(c1.B)
+ p.Pix[i+6] = uint8(c1.A >> 8)
+ p.Pix[i+7] = uint8(c1.A)
}
func (p *NRGBA64) SetNRGBA64(x, y int, c NRGBA64Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8
+ p.Pix[i+0] = uint8(c.R >> 8)
+ p.Pix[i+1] = uint8(c.R)
+ p.Pix[i+2] = uint8(c.G >> 8)
+ p.Pix[i+3] = uint8(c.G)
+ p.Pix[i+4] = uint8(c.B >> 8)
+ p.Pix[i+5] = uint8(c.B)
+ p.Pix[i+6] = uint8(c.A >> 8)
+ p.Pix[i+7] = uint8(c.A)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *NRGBA64) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &NRGBA64{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8
+ return &NRGBA64{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -240,11 +383,10 @@ 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
+ i0, i1 := 6, p.Rect.Dx()*8
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xffff {
+ for i := i0; i < i1; i += 8 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
return false
}
}
@@ -256,14 +398,16 @@ func (p *NRGBA64) Opaque() bool {
// 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}}}
+ pix := make([]uint8, 8*w*h)
+ return &NRGBA64{pix, 8 * w, Rectangle{ZP, Point{w, h}}}
}
-// An Alpha is an in-memory image of AlphaColor values.
+// 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
+ // Pix holds the image's pixels, as alpha values. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -274,24 +418,45 @@ 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}) {
+ if !(Point{x, y}.In(p.Rect)) {
return AlphaColor{}
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ return AlphaColor{p.Pix[i]}
}
func (p *Alpha) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = toAlphaColor(c).(AlphaColor)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = toAlphaColor(c).(AlphaColor).A
}
func (p *Alpha) SetAlpha(x, y int, c AlphaColor) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = c.A
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Alpha) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Alpha{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ return &Alpha{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -299,11 +464,10 @@ 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
+ i0, i1 := 0, p.Rect.Dx()
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xff {
+ for i := i0; i < i1; i++ {
+ if p.Pix[i] != 0xff {
return false
}
}
@@ -315,14 +479,16 @@ func (p *Alpha) Opaque() bool {
// 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}}}
+ pix := make([]uint8, 1*w*h)
+ return &Alpha{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
}
-// An Alpha16 is an in-memory image of Alpha16Color values.
+// 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
+ // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -333,24 +499,48 @@ 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}) {
+ if !(Point{x, y}.In(p.Rect)) {
return Alpha16Color{}
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ return Alpha16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
}
func (p *Alpha16) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ c1 := toAlpha16Color(c).(Alpha16Color)
+ p.Pix[i+0] = uint8(c1.A >> 8)
+ p.Pix[i+1] = uint8(c1.A)
}
func (p *Alpha16) SetAlpha16(x, y int, c Alpha16Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ p.Pix[i+0] = uint8(c.A >> 8)
+ p.Pix[i+1] = uint8(c.A)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Alpha16) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Alpha16{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
+ return &Alpha16{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -358,11 +548,10 @@ 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
+ i0, i1 := 0, p.Rect.Dx()*2
for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
- for _, c := range p.Pix[i0:i1] {
- if c.A != 0xffff {
+ for i := i0; i < i1; i += 2 {
+ if p.Pix[i+0] != 0xff || p.Pix[i+1] != 0xff {
return false
}
}
@@ -374,14 +563,16 @@ func (p *Alpha16) Opaque() bool {
// 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}}}
+ pix := make([]uint8, 2*w*h)
+ return &Alpha16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
}
-// A Gray is an in-memory image of GrayColor values.
+// 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
+ // Pix holds the image's pixels, as gray values. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -392,24 +583,45 @@ 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}) {
+ if !(Point{x, y}.In(p.Rect)) {
return GrayColor{}
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ return GrayColor{p.Pix[i]}
}
func (p *Gray) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = toGrayColor(c).(GrayColor).Y
}
func (p *Gray) SetGray(x, y int, c GrayColor) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = c.Y
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Gray) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Gray{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ return &Gray{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -419,14 +631,16 @@ func (p *Gray) Opaque() bool {
// 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}}}
+ pix := make([]uint8, 1*w*h)
+ return &Gray{pix, 1 * w, Rectangle{ZP, Point{w, h}}}
}
-// A Gray16 is an in-memory image of Gray16Color values.
+// 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
+ // Pix holds the image's pixels, as gray values in big-endian format. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -437,24 +651,48 @@ 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}) {
+ if !(Point{x, y}.In(p.Rect)) {
return Gray16Color{}
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ return Gray16Color{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])}
}
func (p *Gray16) Set(x, y int, c Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color)
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ c1 := toGray16Color(c).(Gray16Color)
+ p.Pix[i+0] = uint8(c1.Y >> 8)
+ p.Pix[i+1] = uint8(c1.Y)
}
func (p *Gray16) SetGray16(x, y int, c Gray16Color) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = c
+ i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2
+ p.Pix[i+0] = uint8(c.Y >> 8)
+ p.Pix[i+1] = uint8(c.Y)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Gray16) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Gray16{}
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2
+ return &Gray16{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: r,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -464,11 +702,11 @@ func (p *Gray16) Opaque() bool {
// 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}}}
+ pix := make([]uint8, 2*w*h)
+ return &Gray16{pix, 2 * w, Rectangle{ZP, Point{w, h}}}
}
-// A PalettedColorModel represents a fixed palette of colors.
+// A PalettedColorModel represents a fixed palette of at most 256 colors.
type PalettedColorModel []Color
func diff(a, b uint32) uint32 {
@@ -483,14 +721,19 @@ func (p PalettedColorModel) Convert(c Color) Color {
if len(p) == 0 {
return nil
}
+ return p[p.Index(c)]
+}
+
+// Index returns the index of the palette color closest to c in Euclidean
+// R,G,B space.
+func (p PalettedColorModel) Index(c Color) int {
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 {
+ ret, bestSSD := 0, uint32(1<<32-1)
+ for i, v := range p {
vr, vg, vb, _ := v.RGBA()
vr >>= 1
vg >>= 1
@@ -498,17 +741,18 @@ func (p PalettedColorModel) Convert(c Color) Color {
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
+ ret, bestSSD = i, ssd
}
}
- return result
+ return ret
}
-// A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
+// Paletted is an in-memory image of uint8 indices into a given palette.
type Paletted struct {
- // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
- Pix []uint8
+ // Pix holds the image's pixels, as palette indices. The pixel at
+ // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
+ Pix []uint8
+ // Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
@@ -524,29 +768,73 @@ func (p *Paletted) At(x, y int) Color {
if len(p.Palette) == 0 {
return nil
}
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return p.Palette[0]
}
- return p.Palette[p.Pix[y*p.Stride+x]]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ return p.Palette[p.Pix[i]]
+}
+
+func (p *Paletted) Set(x, y int, c Color) {
+ if !(Point{x, y}.In(p.Rect)) {
+ return
+ }
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = uint8(p.Palette.Index(c))
}
func (p *Paletted) ColorIndexAt(x, y int) uint8 {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return 0
}
- return p.Pix[y*p.Stride+x]
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ return p.Pix[i]
}
func (p *Paletted) SetColorIndex(x, y int, index uint8) {
- if !p.Rect.Contains(Point{x, y}) {
+ if !(Point{x, y}.In(p.Rect)) {
return
}
- p.Pix[y*p.Stride+x] = index
+ i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X)
+ p.Pix[i] = index
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Paletted) SubImage(r Rectangle) Image {
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Paletted{
+ Palette: p.Palette,
+ }
+ }
+ i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1
+ return &Paletted{
+ Pix: p.Pix[i:],
+ Stride: p.Stride,
+ Rect: p.Rect.Intersect(r),
+ Palette: p.Palette,
+ }
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *Paletted) Opaque() bool {
- for _, c := range p.Palette {
+ var present [256]bool
+ i0, i1 := 0, p.Rect.Dx()
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ present[c] = true
+ }
+ i0 += p.Stride
+ i1 += p.Stride
+ }
+ for i, c := range p.Palette {
+ if !present[i] {
+ continue
+ }
_, _, _, a := c.RGBA()
if a != 0xffff {
return false
@@ -557,6 +845,6 @@ func (p *Paletted) Opaque() bool {
// 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}
+ pix := make([]uint8, 1*w*h)
+ return &Paletted{pix, 1 * w, Rectangle{ZP, Point{w, h}}, m}
}
diff --git a/libgo/go/image/image_test.go b/libgo/go/image/image_test.go
new file mode 100644
index 00000000000..9519acf7906
--- /dev/null
+++ b/libgo/go/image/image_test.go
@@ -0,0 +1,113 @@
+// 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 image_test
+
+import (
+ . "image"
+ "testing"
+)
+
+type image interface {
+ Image
+ Opaque() bool
+ Set(int, int, Color)
+ SubImage(Rectangle) Image
+}
+
+func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
+ r0, g0, b0, a0 := cm.Convert(c0).RGBA()
+ r1, g1, b1, a1 := cm.Convert(c1).RGBA()
+ return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1
+}
+
+func TestImage(t *testing.T) {
+ testImage := []image{
+ NewRGBA(10, 10),
+ NewRGBA64(10, 10),
+ NewNRGBA(10, 10),
+ NewNRGBA64(10, 10),
+ NewAlpha(10, 10),
+ NewAlpha16(10, 10),
+ NewGray(10, 10),
+ NewGray16(10, 10),
+ NewPaletted(10, 10, PalettedColorModel{
+ Transparent,
+ Opaque,
+ }),
+ }
+ for _, m := range testImage {
+ if !Rect(0, 0, 10, 10).Eq(m.Bounds()) {
+ t.Errorf("%T: want bounds %v, got %v", m, Rect(0, 0, 10, 10), m.Bounds())
+ continue
+ }
+ if !cmp(t, m.ColorModel(), Transparent, m.At(6, 3)) {
+ t.Errorf("%T: at (6, 3), want a zero color, got %v", m, m.At(6, 3))
+ continue
+ }
+ m.Set(6, 3, Opaque)
+ if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
+ t.Errorf("%T: at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
+ continue
+ }
+ if !m.SubImage(Rect(6, 3, 7, 4)).(image).Opaque() {
+ t.Errorf("%T: at (6, 3) was not opaque", m)
+ continue
+ }
+ m = m.SubImage(Rect(3, 2, 9, 8)).(image)
+ if !Rect(3, 2, 9, 8).Eq(m.Bounds()) {
+ t.Errorf("%T: sub-image want bounds %v, got %v", m, Rect(3, 2, 9, 8), m.Bounds())
+ continue
+ }
+ if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
+ t.Errorf("%T: sub-image at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
+ continue
+ }
+ if !cmp(t, m.ColorModel(), Transparent, m.At(3, 3)) {
+ t.Errorf("%T: sub-image at (3, 3), want a zero color, got %v", m, m.At(3, 3))
+ continue
+ }
+ m.Set(3, 3, Opaque)
+ if !cmp(t, m.ColorModel(), Opaque, m.At(3, 3)) {
+ t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", m, m.At(3, 3))
+ continue
+ }
+ // Test that taking an empty sub-image starting at a corner does not panic.
+ m.SubImage(Rect(0, 0, 0, 0))
+ m.SubImage(Rect(10, 0, 10, 0))
+ m.SubImage(Rect(0, 10, 0, 10))
+ m.SubImage(Rect(10, 10, 10, 10))
+ }
+}
+
+func Test16BitsPerColorChannel(t *testing.T) {
+ testColorModel := []ColorModel{
+ RGBA64ColorModel,
+ NRGBA64ColorModel,
+ Alpha16ColorModel,
+ Gray16ColorModel,
+ }
+ for _, cm := range testColorModel {
+ c := cm.Convert(RGBA64Color{0x1234, 0x1234, 0x1234, 0x1234}) // Premultiplied alpha.
+ r, _, _, _ := c.RGBA()
+ if r != 0x1234 {
+ t.Errorf("%T: want red value 0x%04x got 0x%04x", c, 0x1234, r)
+ continue
+ }
+ }
+ testImage := []image{
+ NewRGBA64(10, 10),
+ NewNRGBA64(10, 10),
+ NewAlpha16(10, 10),
+ NewGray16(10, 10),
+ }
+ for _, m := range testImage {
+ m.Set(1, 2, NRGBA64Color{0xffff, 0xffff, 0xffff, 0x1357}) // Non-premultiplied alpha.
+ r, _, _, _ := m.At(1, 2).RGBA()
+ if r != 0x1357 {
+ t.Errorf("%T: want red value 0x%04x got 0x%04x", m, 0x1357, r)
+ continue
+ }
+ }
+}
diff --git a/libgo/go/image/jpeg/idct.go b/libgo/go/image/jpeg/idct.go
index e5a2f40f5db..b387dfdffd1 100644
--- a/libgo/go/image/jpeg/idct.go
+++ b/libgo/go/image/jpeg/idct.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+package jpeg
+
// 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
@@ -35,8 +37,6 @@
*
*/
-package jpeg
-
const (
w1 = 2841 // 2048*sqrt(2)*cos(1*pi/16)
w2 = 2676 // 2048*sqrt(2)*cos(2*pi/16)
@@ -55,41 +55,45 @@ const (
r2 = 181 // 256/sqrt(2)
)
-// 2-D Inverse Discrete Cosine Transformation, followed by a +128 level shift.
+// idct performs a 2-D Inverse Discrete Cosine Transformation, followed by a
+// +128 level shift and a clip to [0, 255], writing the results to dst.
+// stride is the number of elements between successive rows of dst.
//
-// 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.
+// 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.
//
-// 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 *block) {
+// 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(dst []byte, stride int, src *block) {
// 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
+ if src[y*8+1] == 0 && src[y*8+2] == 0 && src[y*8+3] == 0 &&
+ src[y*8+4] == 0 && src[y*8+5] == 0 && src[y*8+6] == 0 && src[y*8+7] == 0 {
+ dc := src[y*8+0] << 3
+ src[y*8+0] = dc
+ src[y*8+1] = dc
+ src[y*8+2] = dc
+ src[y*8+3] = dc
+ src[y*8+4] = dc
+ src[y*8+5] = dc
+ src[y*8+6] = dc
+ src[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]
+ x0 := (src[y*8+0] << 11) + 128
+ x1 := src[y*8+4] << 11
+ x2 := src[y*8+6]
+ x3 := src[y*8+2]
+ x4 := src[y*8+1]
+ x5 := src[y*8+7]
+ x6 := src[y*8+5]
+ x7 := src[y*8+3]
// Stage 1.
x8 := w7 * (x4 + x5)
@@ -119,14 +123,14 @@ func idct(b *block) {
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
+ src[8*y+0] = (x7 + x1) >> 8
+ src[8*y+1] = (x3 + x2) >> 8
+ src[8*y+2] = (x0 + x4) >> 8
+ src[8*y+3] = (x8 + x6) >> 8
+ src[8*y+4] = (x8 - x6) >> 8
+ src[8*y+5] = (x0 - x4) >> 8
+ src[8*y+6] = (x3 - x2) >> 8
+ src[8*y+7] = (x7 - x1) >> 8
}
// Vertical 1-D IDCT.
@@ -136,14 +140,14 @@ func idct(b *block) {
// 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]
+ y0 := (src[8*0+x] << 8) + 8192
+ y1 := src[8*4+x] << 8
+ y2 := src[8*6+x]
+ y3 := src[8*2+x]
+ y4 := src[8*1+x]
+ y5 := src[8*7+x]
+ y6 := src[8*5+x]
+ y7 := src[8*3+x]
// Stage 1.
y8 := w7*(y4+y5) + 4
@@ -173,18 +177,28 @@ func idct(b *block) {
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
+ src[8*0+x] = (y7 + y1) >> 14
+ src[8*1+x] = (y3 + y2) >> 14
+ src[8*2+x] = (y0 + y4) >> 14
+ src[8*3+x] = (y8 + y6) >> 14
+ src[8*4+x] = (y8 - y6) >> 14
+ src[8*5+x] = (y0 - y4) >> 14
+ src[8*6+x] = (y3 - y2) >> 14
+ src[8*7+x] = (y7 - y1) >> 14
}
- // Level shift.
- for i := range *b {
- b[i] += 128
+ // Level shift by +128, clip to [0, 255], and write to dst.
+ for y := 0; y < 8; y++ {
+ for x := 0; x < 8; x++ {
+ c := src[y*8+x]
+ if c < -128 {
+ c = 0
+ } else if c > 127 {
+ c = 255
+ } else {
+ c += 128
+ }
+ dst[y*stride+x] = uint8(c)
+ }
}
}
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
index 21a6fff9698..3f22c5271f3 100644
--- a/libgo/go/image/jpeg/reader.go
+++ b/libgo/go/image/jpeg/reader.go
@@ -41,16 +41,22 @@ type block [blockSize]int
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
+ dcTable = 0
+ acTable = 1
+ maxTc = 1
+ maxTh = 3
+ maxTq = 3
+
+ // A grayscale JPEG image has only a Y component.
+ nGrayComponent = 1
+ // A color JPEG image has Y, Cb and Cr components.
+ nColorComponent = 3
+
+ // We only support 4:4:4, 4:2:2 and 4:2:0 downsampling, and therefore the
+ // number of luma samples per chroma sample is at most 2 in the horizontal
+ // and 2 in the vertical direction.
+ maxH = 2
+ maxV = 2
)
const (
@@ -90,13 +96,14 @@ type Reader interface {
type decoder struct {
r Reader
width, height int
- img *ycbcr.YCbCr
+ img1 *image.Gray
+ img3 *ycbcr.YCbCr
ri int // Restart Interval.
- comps [nComponent]component
+ nComp int
+ comp [nColorComponent]component
huff [maxTc + 1][maxTh + 1]huffman
quant [maxTq + 1]block
b bits
- blocks [nComponent][maxH * maxV]block
tmp [1024]byte
}
@@ -118,10 +125,15 @@ func (d *decoder) ignore(n int) os.Error {
// Specified in section B.2.2.
func (d *decoder) processSOF(n int) os.Error {
- if n != 6+3*nComponent {
+ switch n {
+ case 6 + 3*nGrayComponent:
+ d.nComp = nGrayComponent
+ case 6 + 3*nColorComponent:
+ d.nComp = nColorComponent
+ default:
return UnsupportedError("SOF has wrong length")
}
- _, err := io.ReadFull(d.r, d.tmp[0:6+3*nComponent])
+ _, err := io.ReadFull(d.r, d.tmp[:n])
if err != nil {
return err
}
@@ -131,26 +143,28 @@ func (d *decoder) processSOF(n int) os.Error {
}
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 {
+ if int(d.tmp[5]) != d.nComp {
return UnsupportedError("SOF has wrong number of image components")
}
- for i := 0; i < nComponent; i++ {
+ for i := 0; i < d.nComp; i++ {
hv := d.tmp[7+3*i]
- d.comps[i].h = int(hv >> 4)
- d.comps[i].v = int(hv & 0x0f)
- d.comps[i].c = d.tmp[6+3*i]
- 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).
+ d.comp[i].h = int(hv >> 4)
+ d.comp[i].v = int(hv & 0x0f)
+ d.comp[i].c = d.tmp[6+3*i]
+ d.comp[i].tq = d.tmp[8+3*i]
+ if d.nComp == nGrayComponent {
+ continue
+ }
+ // For color images, we only support 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")
- }
+ } else if hv != 0x11 {
+ return UnsupportedError("chroma downsample ratio")
}
}
return nil
@@ -182,110 +196,88 @@ func (d *decoder) processDQT(n int) os.Error {
return nil
}
-// Clip x to the range [0, 255] inclusive.
-func clip(x int) uint8 {
- if x < 0 {
- return 0
- }
- if x > 255 {
- return 255
+// makeImg allocates and initializes the destination image.
+func (d *decoder) makeImg(h0, v0, mxx, myy int) {
+ if d.nComp == nGrayComponent {
+ m := image.NewGray(8*mxx, 8*myy)
+ d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
+ return
}
- return uint8(x)
-}
-
-// Store the MCU to the image.
-func (d *decoder) storeMCU(mx, my int) {
- h0, v0 := d.comps[0].h, d.comps[0].v
- // Store the luma blocks.
- for v := 0; v < v0; v++ {
- for h := 0; h < h0; h++ {
- p := 8 * ((v0*my+v)*d.img.YStride + (h0*mx + h))
- for y := 0; y < 8; y++ {
- for x := 0; x < 8; x++ {
- d.img.Y[p] = clip(d.blocks[0][h0*v+h][8*y+x])
- p++
- }
- p += d.img.YStride - 8
- }
- }
+ var subsampleRatio ycbcr.SubsampleRatio
+ n := h0 * v0
+ switch n {
+ case 1:
+ subsampleRatio = ycbcr.SubsampleRatio444
+ case 2:
+ subsampleRatio = ycbcr.SubsampleRatio422
+ case 4:
+ subsampleRatio = ycbcr.SubsampleRatio420
+ default:
+ panic("unreachable")
}
- // Store the chroma blocks.
- p := 8 * (my*d.img.CStride + mx)
- for y := 0; y < 8; y++ {
- for x := 0; x < 8; x++ {
- d.img.Cb[p] = clip(d.blocks[1][0][8*y+x])
- d.img.Cr[p] = clip(d.blocks[2][0][8*y+x])
- p++
- }
- p += d.img.CStride - 8
+ b := make([]byte, mxx*myy*(1*8*8*n+2*8*8))
+ d.img3 = &ycbcr.YCbCr{
+ Y: b[mxx*myy*(0*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+0*8*8)],
+ Cb: b[mxx*myy*(1*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+1*8*8)],
+ Cr: b[mxx*myy*(1*8*8*n+1*8*8) : mxx*myy*(1*8*8*n+2*8*8)],
+ SubsampleRatio: subsampleRatio,
+ YStride: mxx * 8 * h0,
+ CStride: mxx * 8,
+ Rect: image.Rect(0, 0, d.width, d.height),
}
}
// Specified in section B.2.3.
func (d *decoder) processSOS(n int) os.Error {
- if n != 4+2*nComponent {
+ if d.nComp == 0 {
+ return FormatError("missing SOF marker")
+ }
+ if n != 4+2*d.nComp {
return UnsupportedError("SOS has wrong length")
}
- _, err := io.ReadFull(d.r, d.tmp[0:4+2*nComponent])
+ _, err := io.ReadFull(d.r, d.tmp[0:4+2*d.nComp])
if err != nil {
return err
}
- if d.tmp[0] != nComponent {
+ if int(d.tmp[0]) != d.nComp {
return UnsupportedError("SOS has wrong number of image components")
}
- var scanComps [nComponent]struct {
+ var scan [nColorComponent]struct {
td uint8 // DC table selector.
ta uint8 // AC table selector.
}
- for i := 0; i < nComponent; i++ {
+ for i := 0; i < d.nComp; i++ {
cs := d.tmp[1+2*i] // Component selector.
- if cs != d.comps[i].c {
+ if cs != d.comp[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
+ scan[i].td = d.tmp[2+2*i] >> 4
+ scan[i].ta = d.tmp[2+2*i] & 0x0f
}
// mxx and myy are the number of MCUs (Minimum Coded Units) in the image.
- h0, v0 := d.comps[0].h, d.comps[0].v // The h and v values from the Y components.
+ h0, v0 := d.comp[0].h, d.comp[0].v // The h and v values from the Y components.
mxx := (d.width + 8*h0 - 1) / (8 * h0)
myy := (d.height + 8*v0 - 1) / (8 * v0)
- if d.img == nil {
- var subsampleRatio ycbcr.SubsampleRatio
- n := h0 * v0
- switch n {
- case 1:
- subsampleRatio = ycbcr.SubsampleRatio444
- case 2:
- subsampleRatio = ycbcr.SubsampleRatio422
- case 4:
- subsampleRatio = ycbcr.SubsampleRatio420
- default:
- panic("unreachable")
- }
- b := make([]byte, mxx*myy*(1*8*8*n+2*8*8))
- d.img = &ycbcr.YCbCr{
- Y: b[mxx*myy*(0*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+0*8*8)],
- Cb: b[mxx*myy*(1*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+1*8*8)],
- Cr: b[mxx*myy*(1*8*8*n+1*8*8) : mxx*myy*(1*8*8*n+2*8*8)],
- SubsampleRatio: subsampleRatio,
- YStride: mxx * 8 * h0,
- CStride: mxx * 8,
- Rect: image.Rect(0, 0, d.width, d.height),
- }
+ if d.img1 == nil && d.img3 == nil {
+ d.makeImg(h0, v0, mxx, myy)
}
mcu, expectedRST := 0, uint8(rst0Marker)
- var allZeroes block
- var dc [nComponent]int
+ var (
+ b block
+ dc [nColorComponent]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 < d.comps[i].h*d.comps[i].v; j++ {
- d.blocks[i][j] = allZeroes
+ for i := 0; i < d.nComp; i++ {
+ qt := &d.quant[d.comp[i].tq]
+ for j := 0; j < d.comp[i].h*d.comp[i].v; j++ {
+ // TODO(nigeltao): make this a "var b block" once the compiler's escape
+ // analysis is good enough to allocate it on the stack, not the heap.
+ b = block{}
// Decode the DC coefficient, as specified in section F.2.2.1.
- value, err := d.decodeHuffman(&d.huff[dcTableClass][scanComps[i].td])
+ value, err := d.decodeHuffman(&d.huff[dcTable][scan[i].td])
if err != nil {
return err
}
@@ -297,11 +289,11 @@ func (d *decoder) processSOS(n int) os.Error {
return err
}
dc[i] += dcDelta
- d.blocks[i][j][0] = dc[i] * qt[0]
+ b[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])
+ value, err := d.decodeHuffman(&d.huff[acTable][scan[i].ta])
if err != nil {
return err
}
@@ -316,7 +308,7 @@ func (d *decoder) processSOS(n int) os.Error {
if err != nil {
return err
}
- d.blocks[i][j][unzig[k]] = ac * qt[k]
+ b[unzig[k]] = ac * qt[k]
} else {
if val0 != 0x0f {
break
@@ -325,10 +317,23 @@ func (d *decoder) processSOS(n int) os.Error {
}
}
- idct(&d.blocks[i][j])
+ // Perform the inverse DCT and store the MCU component to the image.
+ if d.nComp == nGrayComponent {
+ idct(d.img1.Pix[8*(my*d.img1.Stride+mx):], d.img1.Stride, &b)
+ } else {
+ switch i {
+ case 0:
+ mx0 := h0*mx + (j % 2)
+ my0 := v0*my + (j / 2)
+ idct(d.img3.Y[8*(my0*d.img3.YStride+mx0):], d.img3.YStride, &b)
+ case 1:
+ idct(d.img3.Cb[8*(my*d.img3.CStride+mx):], d.img3.CStride, &b)
+ case 2:
+ idct(d.img3.Cr[8*(my*d.img3.CStride+mx):], d.img3.CStride, &b)
+ }
+ }
} // for j
} // for i
- d.storeMCU(mx, my)
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,
@@ -347,9 +352,7 @@ func (d *decoder) processSOS(n int) os.Error {
// 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
- }
+ dc = [nColorComponent]int{}
}
} // for mx
} // for my
@@ -437,7 +440,13 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, os.Error) {
return nil, err
}
}
- return d.img, nil
+ if d.img1 != nil {
+ return d.img1, nil
+ }
+ if d.img3 != nil {
+ return d.img3, nil
+ }
+ return nil, FormatError("missing SOS marker")
}
// Decode reads a JPEG image from r and returns it as an image.Image.
@@ -453,7 +462,13 @@ func DecodeConfig(r io.Reader) (image.Config, os.Error) {
if _, err := d.decode(r, true); err != nil {
return image.Config{}, err
}
- return image.Config{image.RGBAColorModel, d.width, d.height}, nil
+ switch d.nComp {
+ case nGrayComponent:
+ return image.Config{image.GrayColorModel, d.width, d.height}, nil
+ case nColorComponent:
+ return image.Config{ycbcr.YCbCrColorModel, d.width, d.height}, nil
+ }
+ return image.Config{}, FormatError("missing SOF marker")
}
func init() {
diff --git a/libgo/go/image/jpeg/writer.go b/libgo/go/image/jpeg/writer.go
index 52b3dc4e2c1..2bb6df5dd1b 100644
--- a/libgo/go/image/jpeg/writer.go
+++ b/libgo/go/image/jpeg/writer.go
@@ -221,8 +221,7 @@ type encoder struct {
// buf is a scratch buffer.
buf [16]byte
// bits and nBits are accumulated bits to write to w.
- bits uint32
- nBits uint8
+ bits, nBits uint32
// quant is the scaled quantization tables.
quant [nQuantIndex][blockSize]byte
}
@@ -250,7 +249,7 @@ func (e *encoder) writeByte(b byte) {
// emit emits the least significant nBits bits of bits to the bitstream.
// The precondition is bits < 1<<nBits && nBits <= 16.
-func (e *encoder) emit(bits uint32, nBits uint8) {
+func (e *encoder) emit(bits, nBits uint32) {
nBits += e.nBits
bits <<= 32 - nBits
bits |= e.bits
@@ -269,7 +268,7 @@ func (e *encoder) emit(bits uint32, nBits uint8) {
// emitHuff emits the given value with the given Huffman encoder.
func (e *encoder) emitHuff(h huffIndex, value int) {
x := theHuffmanLUT[h][value]
- e.emit(x&(1<<24-1), uint8(x>>24))
+ e.emit(x&(1<<24-1), x>>24)
}
// emitHuffRLE emits a run of runLength copies of value encoded with the given
@@ -279,11 +278,11 @@ func (e *encoder) emitHuffRLE(h huffIndex, runLength, value int) {
if a < 0 {
a, b = -value, value-1
}
- var nBits uint8
+ var nBits uint32
if a < 0x100 {
- nBits = bitCount[a]
+ nBits = uint32(bitCount[a])
} else {
- nBits = 8 + bitCount[a>>8]
+ nBits = 8 + uint32(bitCount[a>>8])
}
e.emitHuff(h, runLength<<4|int(nBits))
if nBits > 0 {
@@ -302,34 +301,31 @@ func (e *encoder) writeMarkerHeader(marker uint8, markerlen int) {
// writeDQT writes the Define Quantization Table marker.
func (e *encoder) writeDQT() {
- markerlen := 2
- for _, q := range e.quant {
- markerlen += 1 + len(q)
- }
+ markerlen := 2 + int(nQuantIndex)*(1+blockSize)
e.writeMarkerHeader(dqtMarker, markerlen)
- for i, q := range e.quant {
+ for i := range e.quant {
e.writeByte(uint8(i))
- e.write(q[:])
+ e.write(e.quant[i][:])
}
}
// writeSOF0 writes the Start Of Frame (Baseline) marker.
func (e *encoder) writeSOF0(size image.Point) {
- markerlen := 8 + 3*nComponent
+ markerlen := 8 + 3*nColorComponent
e.writeMarkerHeader(sof0Marker, markerlen)
e.buf[0] = 8 // 8-bit color.
e.buf[1] = uint8(size.Y >> 8)
e.buf[2] = uint8(size.Y & 0xff)
e.buf[3] = uint8(size.X >> 8)
e.buf[4] = uint8(size.X & 0xff)
- e.buf[5] = nComponent
- for i := 0; i < nComponent; i++ {
+ e.buf[5] = nColorComponent
+ for i := 0; i < nColorComponent; i++ {
e.buf[3*i+6] = uint8(i + 1)
// We use 4:2:0 chroma subsampling.
e.buf[3*i+7] = "\x22\x11\x11"[i]
e.buf[3*i+8] = "\x00\x01\x01"[i]
}
- e.write(e.buf[:3*(nComponent-1)+9])
+ e.write(e.buf[:3*(nColorComponent-1)+9])
}
// writeDHT writes the Define Huffman Table marker.
@@ -401,14 +397,14 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
if sj > ymax {
sj = ymax
}
- yoff := sj * m.Stride
+ offset := (sj-b.Min.Y)*m.Stride - b.Min.X*4
for i := 0; i < 8; i++ {
sx := p.X + i
if sx > xmax {
sx = xmax
}
- col := &m.Pix[yoff+sx]
- yy, cb, cr := ycbcr.RGBToYCbCr(col.R, col.G, col.B)
+ pix := m.Pix[offset+sx*4:]
+ yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
yBlock[8*j+i] = int(yy)
cbBlock[8*j+i] = int(cb)
crBlock[8*j+i] = int(cr)
diff --git a/libgo/go/image/png/writer.go b/libgo/go/image/png/writer.go
index a27586f2394..55ca97e0628 100644
--- a/libgo/go/image/png/writer.go
+++ b/libgo/go/image/png/writer.go
@@ -174,7 +174,7 @@ func (e *encoder) Write(b []byte) (int, os.Error) {
// 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 {
+func filter(cr *[nFilter][]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
@@ -275,11 +275,6 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
bpp := 0 // Bytes per pixel.
- // Used by fast paths for common image types
- var paletted *image.Paletted
- var rgba *image.RGBA
- rgba, _ = m.(*image.RGBA)
-
switch cb {
case cbG8:
bpp = 1
@@ -287,7 +282,6 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
bpp = 3
case cbP8:
bpp = 1
- paletted = m.(*image.Paletted)
case cbTCA8:
bpp = 4
case cbTC16:
@@ -304,7 +298,7 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
// 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++ {
+ for i := range cr {
cr[i] = make([]uint8, 1+bpp*b.Dx())
cr[i][0] = uint8(i)
}
@@ -312,78 +306,86 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
for y := b.Min.Y; y < b.Max.Y; y++ {
// Convert from colors to bytes.
+ i := 1
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
+ cr[0][i] = c.Y
+ i++
}
case cbTC8:
// We have previously verified that the alpha value is fully opaque.
cr0 := cr[0]
- if rgba != nil {
- yoff := y * rgba.Stride
- xoff := 3*b.Min.X + 1
- for _, color := range rgba.Pix[yoff+b.Min.X : yoff+b.Max.X] {
- cr0[xoff] = color.R
- cr0[xoff+1] = color.G
- cr0[xoff+2] = color.B
- xoff += 3
+ if rgba, _ := m.(*image.RGBA); rgba != nil {
+ j0 := (y - b.Min.Y) * rgba.Stride
+ j1 := j0 + b.Dx()*4
+ for j := j0; j < j1; j += 4 {
+ cr0[i+0] = rgba.Pix[j+0]
+ cr0[i+1] = rgba.Pix[j+1]
+ cr0[i+2] = rgba.Pix[j+2]
+ i += 3
}
} else {
for x := b.Min.X; x < b.Max.X; x++ {
r, g, b, _ := m.At(x, y).RGBA()
- cr0[3*x+1] = uint8(r >> 8)
- cr0[3*x+2] = uint8(g >> 8)
- cr0[3*x+3] = uint8(b >> 8)
+ cr0[i+0] = uint8(r >> 8)
+ cr0[i+1] = uint8(g >> 8)
+ cr0[i+2] = uint8(b >> 8)
+ i += 3
}
}
case cbP8:
- rowOffset := y * paletted.Stride
- copy(cr[0][b.Min.X+1:], paletted.Pix[rowOffset+b.Min.X:rowOffset+b.Max.X])
+ paletted := m.(*image.Paletted)
+ offset := (y - b.Min.Y) * paletted.Stride
+ copy(cr[0][1:], paletted.Pix[offset:offset+b.Dx()])
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
+ cr[0][i+0] = c.R
+ cr[0][i+1] = c.G
+ cr[0][i+2] = c.B
+ cr[0][i+3] = c.A
+ i += 4
}
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)
+ cr[0][i+0] = uint8(c.Y >> 8)
+ cr[0][i+1] = uint8(c.Y)
+ i += 2
}
case cbTC16:
+ // We have previously verified that the alpha value is fully opaque.
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)
+ cr[0][i+0] = uint8(r >> 8)
+ cr[0][i+1] = uint8(r)
+ cr[0][i+2] = uint8(g >> 8)
+ cr[0][i+3] = uint8(g)
+ cr[0][i+4] = uint8(b >> 8)
+ cr[0][i+5] = uint8(b)
+ i += 6
}
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)
+ cr[0][i+0] = uint8(c.R >> 8)
+ cr[0][i+1] = uint8(c.R)
+ cr[0][i+2] = uint8(c.G >> 8)
+ cr[0][i+3] = uint8(c.G)
+ cr[0][i+4] = uint8(c.B >> 8)
+ cr[0][i+5] = uint8(c.B)
+ cr[0][i+6] = uint8(c.A >> 8)
+ cr[0][i+7] = uint8(c.A)
+ i += 8
}
}
// Apply the filter.
- f := filter(cr[0:nFilter], pr, bpp)
+ f := filter(&cr, pr, bpp)
// Write the compressed bytes.
_, err = zw.Write(cr[f])
diff --git a/libgo/go/image/png/writer_test.go b/libgo/go/image/png/writer_test.go
index 6b054aaa893..1599791b3a3 100644
--- a/libgo/go/image/png/writer_test.go
+++ b/libgo/go/image/png/writer_test.go
@@ -5,9 +5,9 @@
package png
import (
+ "bytes"
"fmt"
"image"
- "io"
"io/ioutil"
"os"
"testing"
@@ -15,21 +15,38 @@ import (
func diff(m0, m1 image.Image) os.Error {
b0, b1 := m0.Bounds(), m1.Bounds()
- if !b0.Eq(b1) {
+ if !b0.Size().Eq(b1.Size()) {
return fmt.Errorf("dimensions differ: %v vs %v", b0, b1)
}
+ dx := b1.Min.X - b0.Min.X
+ dy := b1.Min.Y - b0.Min.Y
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()
+ c0 := m0.At(x, y)
+ c1 := m1.At(x+dx, y+dy)
+ r0, g0, b0, a0 := c0.RGBA()
+ r1, g1, b1, a1 := c1.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 fmt.Errorf("colors differ at (%d, %d): %v vs %v", x, y, c0, c1)
}
}
}
return nil
}
+func encodeDecode(m image.Image) (image.Image, os.Error) {
+ b := bytes.NewBuffer(nil)
+ err := Encode(b, m)
+ if err != nil {
+ return nil, err
+ }
+ m, err = Decode(b)
+ if err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
func TestWriter(t *testing.T) {
// The filenames variable is declared in reader_test.go.
names := filenames
@@ -44,26 +61,16 @@ func TestWriter(t *testing.T) {
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)
+ // Read the image again, encode it, and decode it.
+ m1, err := readPng(qfn)
if err != nil {
t.Error(fn, err)
- continue
+ return
+ }
+ m2, err := encodeDecode(m1)
+ if err != nil {
+ t.Error(fn, err)
+ return
}
// Compare the two.
err = diff(m0, m2)
@@ -74,6 +81,26 @@ func TestWriter(t *testing.T) {
}
}
+func TestSubImage(t *testing.T) {
+ m0 := image.NewRGBA(256, 256)
+ for y := 0; y < 256; y++ {
+ for x := 0; x < 256; x++ {
+ m0.Set(x, y, image.RGBAColor{uint8(x), uint8(y), 0, 255})
+ }
+ }
+ m0 = m0.SubImage(image.Rect(50, 30, 250, 130)).(*image.RGBA)
+ m1, err := encodeDecode(m0)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ err = diff(m0, m1)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+}
+
func BenchmarkEncodePaletted(b *testing.B) {
b.StopTimer()
img := image.NewPaletted(640, 480,
diff --git a/libgo/go/image/testdata/video-001.5bpp.gif b/libgo/go/image/testdata/video-001.5bpp.gif
new file mode 100644
index 00000000000..ce53104b2d2
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.5bpp.gif
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.interlaced.gif b/libgo/go/image/testdata/video-001.interlaced.gif
new file mode 100644
index 00000000000..590594ea9a7
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.interlaced.gif
Binary files differ
diff --git a/libgo/go/image/testdata/video-005.gray.jpeg b/libgo/go/image/testdata/video-005.gray.jpeg
new file mode 100644
index 00000000000..f9d6e5cdb41
--- /dev/null
+++ b/libgo/go/image/testdata/video-005.gray.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-005.gray.png b/libgo/go/image/testdata/video-005.gray.png
new file mode 100644
index 00000000000..0b0ee753845
--- /dev/null
+++ b/libgo/go/image/testdata/video-005.gray.png
Binary files differ
diff --git a/libgo/go/image/tiff/consts.go b/libgo/go/image/tiff/consts.go
index 761ac9d9094..169ba27721d 100644
--- a/libgo/go/image/tiff/consts.go
+++ b/libgo/go/image/tiff/consts.go
@@ -54,6 +54,7 @@ const (
tPredictor = 317
tColorMap = 320
tExtraSamples = 338
+ tSampleFormat = 339
)
// Compression types (defined in various places in the spec and supplements).
diff --git a/libgo/go/image/tiff/reader.go b/libgo/go/image/tiff/reader.go
index 40f659c36c8..f5652667aa3 100644
--- a/libgo/go/image/tiff/reader.go
+++ b/libgo/go/image/tiff/reader.go
@@ -46,6 +46,11 @@ type decoder struct {
mode imageMode
features map[int][]uint
palette []image.Color
+
+ buf []byte
+ off int // Current offset in buf.
+ v uint32 // Buffer value for reading with arbitrary bit depths.
+ nbits uint // Remaining number of bits in v.
}
// firstVal returns the first uint of the features entry with the given tag,
@@ -133,82 +138,112 @@ func (d *decoder) parseIFD(p []byte) os.Error {
0xffff,
}
}
+ case tSampleFormat:
+ // Page 27 of the spec: If the SampleFormat is present and
+ // the value is not 1 [= unsigned integer data], a Baseline
+ // TIFF reader that cannot handle the SampleFormat value
+ // must terminate the import process gracefully.
+ val, err := d.ifdUint(p)
+ if err != nil {
+ return err
+ }
+ for _, v := range val {
+ if v != 1 {
+ return UnsupportedError("sample format")
+ }
+ }
}
return nil
}
-// decode decodes the raw data of an image with 8 bits in each sample.
-// It reads from p and writes the strip with ymin <= y < ymax into dst.
-func (d *decoder) decode(dst image.Image, p []byte, ymin, ymax int) os.Error {
+// readBits reads n bits from the internal buffer starting at the current offset.
+func (d *decoder) readBits(n uint) uint32 {
+ for d.nbits < n {
+ d.v <<= 8
+ d.v |= uint32(d.buf[d.off])
+ d.off++
+ d.nbits += 8
+ }
+ d.nbits -= n
+ rv := d.v >> d.nbits
+ d.v &^= rv << d.nbits
+ return rv
+}
+
+// flushBits discards the unread bits in the buffer used by readBits.
+// It is used at the end of a line.
+func (d *decoder) flushBits() {
+ d.v = 0
+ d.nbits = 0
+}
+
+// decode decodes the raw data of an image.
+// It reads from d.buf and writes the strip with ymin <= y < ymax into dst.
+func (d *decoder) decode(dst image.Image, ymin, ymax int) os.Error {
spp := len(d.features[tBitsPerSample]) // samples per pixel
- off := 0
+ d.off = 0
width := dst.Bounds().Dx()
- if len(p) < spp*(ymax-ymin)*width {
- return FormatError("short data strip")
- }
-
// Apply horizontal predictor if necessary.
// In this case, p contains the color difference to the preceding pixel.
// See page 64-65 of the spec.
- if d.firstVal(tPredictor) == prHorizontal {
+ if d.firstVal(tPredictor) == prHorizontal && d.firstVal(tBitsPerSample) == 8 {
for y := ymin; y < ymax; y++ {
- off += spp
+ d.off += spp
for x := 0; x < (width-1)*spp; x++ {
- p[off] += p[off-spp]
- off++
+ d.buf[d.off] += d.buf[d.off-spp]
+ d.off++
}
}
- off = 0
+ d.off = 0
}
switch d.mode {
- case mGray:
- img := dst.(*image.Gray)
- for y := ymin; y < ymax; y++ {
- for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.GrayColor{p[off]})
- off += spp
- }
- }
- case mGrayInvert:
+ case mGray, mGrayInvert:
img := dst.(*image.Gray)
+ bpp := d.firstVal(tBitsPerSample)
+ max := uint32((1 << bpp) - 1)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.GrayColor{0xff - p[off]})
- off += spp
+ v := uint8(d.readBits(bpp) * 0xff / max)
+ if d.mode == mGrayInvert {
+ v = 0xff - v
+ }
+ img.SetGray(x, y, image.GrayColor{v})
}
+ d.flushBits()
}
case mPaletted:
img := dst.(*image.Paletted)
+ bpp := d.firstVal(tBitsPerSample)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.SetColorIndex(x, y, p[off])
- off += spp
+ img.SetColorIndex(x, y, uint8(d.readBits(bpp)))
}
+ d.flushBits()
}
case mRGB:
img := dst.(*image.RGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.RGBAColor{p[off], p[off+1], p[off+2], 0xff})
- off += spp
+ img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], 0xff})
+ d.off += spp
}
}
case mNRGBA:
img := dst.(*image.NRGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.NRGBAColor{p[off], p[off+1], p[off+2], p[off+3]})
- off += spp
+ img.SetNRGBA(x, y, image.NRGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], d.buf[d.off+3]})
+ d.off += spp
}
}
case mRGBA:
img := dst.(*image.RGBA)
for y := ymin; y < ymax; y++ {
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
- img.Set(x, y, image.RGBAColor{p[off], p[off+1], p[off+2], p[off+3]})
- off += spp
+ img.SetRGBA(x, y, image.RGBAColor{d.buf[d.off], d.buf[d.off+1], d.buf[d.off+2], d.buf[d.off+3]})
+ d.off += spp
}
}
}
@@ -258,9 +293,18 @@ func newDecoder(r io.Reader) (*decoder, os.Error) {
d.config.Width = int(d.firstVal(tImageWidth))
d.config.Height = int(d.firstVal(tImageLength))
+ if _, ok := d.features[tBitsPerSample]; !ok {
+ return nil, FormatError("BitsPerSample tag missing")
+ }
+
// Determine the image mode.
switch d.firstVal(tPhotometricInterpretation) {
case pRGB:
+ for _, b := range d.features[tBitsPerSample] {
+ if b != 8 {
+ return nil, UnsupportedError("non-8-bit RGB image")
+ }
+ }
d.config.ColorModel = image.RGBAColorModel
// RGB images normally have 3 samples per pixel.
// If there are more, ExtraSamples (p. 31-32 of the spec)
@@ -295,15 +339,6 @@ func newDecoder(r io.Reader) (*decoder, os.Error) {
return nil, UnsupportedError("color model")
}
- if _, ok := d.features[tBitsPerSample]; !ok {
- return nil, FormatError("BitsPerSample tag missing")
- }
- for _, b := range d.features[tBitsPerSample] {
- if b != 8 {
- return nil, UnsupportedError("not an 8-bit image")
- }
- }
-
return d, nil
}
@@ -327,6 +362,10 @@ func Decode(r io.Reader) (img image.Image, err os.Error) {
// Check if we have the right number of strips, offsets and counts.
rps := int(d.firstVal(tRowsPerStrip))
+ if rps == 0 {
+ // Assume only one strip.
+ rps = d.config.Height
+ }
numStrips := (d.config.Height + rps - 1) / rps
if rps == 0 || len(d.features[tStripOffsets]) < numStrips || len(d.features[tStripByteCounts]) < numStrips {
return nil, FormatError("inconsistent header")
@@ -343,7 +382,6 @@ func Decode(r io.Reader) (img image.Image, err os.Error) {
img = image.NewRGBA(d.config.Width, d.config.Height)
}
- var p []byte
for i := 0; i < numStrips; i++ {
ymin := i * rps
// The last strip may be shorter.
@@ -355,18 +393,18 @@ func Decode(r io.Reader) (img image.Image, err os.Error) {
switch d.firstVal(tCompression) {
case cNone:
// TODO(bsiegert): Avoid copy if r is a tiff.buffer.
- p = make([]byte, 0, n)
- _, err = d.r.ReadAt(p, offset)
+ d.buf = make([]byte, n)
+ _, err = d.r.ReadAt(d.buf, offset)
case cLZW:
r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
- p, err = ioutil.ReadAll(r)
+ d.buf, err = ioutil.ReadAll(r)
r.Close()
case cDeflate, cDeflateOld:
r, err := zlib.NewReader(io.NewSectionReader(d.r, offset, n))
if err != nil {
return nil, err
}
- p, err = ioutil.ReadAll(r)
+ d.buf, err = ioutil.ReadAll(r)
r.Close()
default:
err = UnsupportedError("compression")
@@ -374,7 +412,7 @@ func Decode(r io.Reader) (img image.Image, err os.Error) {
if err != nil {
return
}
- err = d.decode(img, p, ymin, ymin+rps)
+ err = d.decode(img, ymin, ymin+rps)
}
return
}
diff --git a/libgo/go/image/tiff/reader_test.go b/libgo/go/image/tiff/reader_test.go
new file mode 100644
index 00000000000..f2122c44038
--- /dev/null
+++ b/libgo/go/image/tiff/reader_test.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.
+
+package tiff
+
+import (
+ "os"
+ "testing"
+)
+
+// TestNoRPS tries to decode an image that has no RowsPerStrip tag.
+// The tag is mandatory according to the spec but some software omits
+// it in the case of a single strip.
+func TestNoRPS(t *testing.T) {
+ f, err := os.Open("testdata/no_rps.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ _, err = Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/libgo/go/image/tiff/testdata/no_rps.tiff b/libgo/go/image/tiff/testdata/no_rps.tiff
new file mode 100644
index 00000000000..3280cf8e344
--- /dev/null
+++ b/libgo/go/image/tiff/testdata/no_rps.tiff
Binary files differ
diff --git a/libgo/go/image/ycbcr/ycbcr.go b/libgo/go/image/ycbcr/ycbcr.go
index cda45996df0..f2de3d6fbc5 100644
--- a/libgo/go/image/ycbcr/ycbcr.go
+++ b/libgo/go/image/ycbcr/ycbcr.go
@@ -142,7 +142,7 @@ func (p *YCbCr) Bounds() image.Rectangle {
}
func (p *YCbCr) At(x, y int) image.Color {
- if !p.Rect.Contains(image.Point{x, y}) {
+ if !(image.Point{x, y}.In(p.Rect)) {
return YCbCrColor{}
}
switch p.SubsampleRatio {
@@ -169,6 +169,15 @@ func (p *YCbCr) At(x, y int) image.Color {
}
}
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *YCbCr) SubImage(r image.Rectangle) image.Image {
+ q := new(YCbCr)
+ *q = *p
+ q.Rect = q.Rect.Intersect(r)
+ return q
+}
+
func (p *YCbCr) Opaque() bool {
return true
}
diff --git a/libgo/go/index/suffixarray/qsufsort.go b/libgo/go/index/suffixarray/qsufsort.go
index 9751b5c7663..30c1104428c 100644
--- a/libgo/go/index/suffixarray/qsufsort.go
+++ b/libgo/go/index/suffixarray/qsufsort.go
@@ -72,7 +72,6 @@ func qsufsort(data []byte) []int {
return sa
}
-
func sortedByFirstByte(data []byte) []int {
// total byte counts
var count [256]int
@@ -93,7 +92,6 @@ func sortedByFirstByte(data []byte) []int {
return sa
}
-
func initGroups(sa []int, data []byte) []int {
// label contiguous same-letter groups with the same group number
inv := make([]int, len(data))
@@ -133,7 +131,6 @@ func initGroups(sa []int, data []byte) []int {
return inv
}
-
type suffixSortable struct {
sa []int
inv []int
@@ -144,7 +141,6 @@ 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) {
bounds := make([]int, 0, 4)
group := x.inv[x.sa[0]+x.h]
diff --git a/libgo/go/index/suffixarray/suffixarray.go b/libgo/go/index/suffixarray/suffixarray.go
index 079b7d8ed0b..82e98d2ef54 100644
--- a/libgo/go/index/suffixarray/suffixarray.go
+++ b/libgo/go/index/suffixarray/suffixarray.go
@@ -22,21 +22,18 @@ import (
"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.
//
@@ -44,12 +41,10 @@ func (x *Index) Bytes() []byte {
return x.data
}
-
func (x *Index) at(i int) []byte {
return x.data[x.sa[i]:]
}
-
// lookupAll returns a slice into the matching region of the index.
// The runtime is O(log(N)*len(s)).
func (x *Index) lookupAll(s []byte) []int {
@@ -61,7 +56,6 @@ func (x *Index) lookupAll(s []byte) []int {
return x.sa[i:j]
}
-
// 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.
@@ -82,7 +76,6 @@ func (x *Index) Lookup(s []byte, n int) (result []int) {
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
@@ -115,7 +108,7 @@ func (x *Index) FindAllIndex(r *regexp.Regexp, n int) (result [][]int) {
if len(indices) == 0 {
return
}
- sort.SortInts(indices)
+ sort.Ints(indices)
pairs := make([]int, 2*len(indices))
result = make([][]int, len(indices))
count := 0
@@ -159,7 +152,7 @@ func (x *Index) FindAllIndex(r *regexp.Regexp, n int) (result [][]int) {
if len(indices) == 0 {
return
}
- sort.SortInts(indices)
+ sort.Ints(indices)
result = result[0:0]
prev := 0
for _, i := range indices {
diff --git a/libgo/go/index/suffixarray/suffixarray_test.go b/libgo/go/index/suffixarray/suffixarray_test.go
index e85267f17f5..02374850056 100644
--- a/libgo/go/index/suffixarray/suffixarray_test.go
+++ b/libgo/go/index/suffixarray/suffixarray_test.go
@@ -6,21 +6,18 @@ 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",
@@ -107,10 +104,9 @@ var testCases = []testCase{
},
}
-
-// find all occurrences of s in source; report at most n occurences
+// find all occurrences of s in source; report at most n occurrences
func find(src, s string, n int) []int {
- var res vector.IntVector
+ var res []int
if s != "" && n != 0 {
// find at most n occurrences of s in src
for i := -1; n < 0 || len(res) < n; {
@@ -119,13 +115,12 @@ func find(src, s string, n int) []int {
break
}
i += j + 1
- res.Push(i)
+ res = append(res, 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)
@@ -141,7 +136,7 @@ func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
// 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)
+ sort.Ints(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))
@@ -164,7 +159,6 @@ func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
}
}
-
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)
@@ -200,7 +194,6 @@ func testFindAllIndex(t *testing.T, tc *testCase, x *Index, rx *regexp.Regexp, n
}
}
-
func testLookups(t *testing.T, tc *testCase, x *Index, n int) {
for _, pat := range tc.patterns {
testLookup(t, tc, x, pat, n)
@@ -210,7 +203,6 @@ func testLookups(t *testing.T, tc *testCase, x *Index, n int) {
}
}
-
// index is used to hide the sort.Interface
type index Index
@@ -219,14 +211,12 @@ 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))
diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go
index 0bc73d67dd9..b879fe5b721 100644
--- a/libgo/go/io/io.go
+++ b/libgo/go/io/io.go
@@ -12,9 +12,11 @@ import "os"
// Error represents an unexpected I/O behavior.
type Error struct {
- os.ErrorString
+ ErrorString string
}
+func (err *Error) String() string { return err.ErrorString }
+
// ErrShortWrite means that a write accepted fewer bytes than requested
// but failed to return an explicit error.
var ErrShortWrite os.Error = &Error{"short write"}
@@ -29,15 +31,24 @@ var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}
// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p. It returns the number of bytes
-// read (0 <= n <= len(p)) and any error encountered.
-// Even if Read returns n < len(p),
-// it may use all of p as scratch space during the call.
+// read (0 <= n <= len(p)) and any error encountered. Even if Read
+// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
-// returns what is available rather than block waiting for more.
+// returns what is available instead of waiting for more.
//
-// 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.
+// When Read encounters an error or end-of-file condition after
+// successfully reading n > 0 bytes, it returns the number of
+// bytes read. It may return the (non-nil) error from the same call
+// or return the error (and n == 0) from a subsequent call.
+// An instance of this general case is that a Reader returning
+// a non-zero number of bytes at the end of the input stream may
+// return either err == os.EOF or err == nil. The next Read should
+// return 0, os.EOF regardless.
+//
+// Callers should always process the n > 0 bytes returned before
+// considering the error err. Doing so correctly handles I/O errors
+// that happen after reading some bytes and also both of the
+// allowed EOF behaviors.
type Reader interface {
Read(p []byte) (n int, err os.Error)
}
@@ -125,19 +136,22 @@ type WriterTo interface {
// ReaderAt is the interface that wraps the basic ReadAt method.
//
// ReadAt reads len(p) bytes into p starting at offset off in the
-// underlying data stream. It returns the number of bytes
+// underlying input source. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
//
-// Even if ReadAt returns n < len(p),
-// it may use all of p as scratch space during the call.
-// If some data is available but not len(p) bytes, ReadAt blocks
-// until either all the data is available or an error occurs.
+// When ReadAt returns n < len(p), it returns a non-nil error
+// explaining why more bytes were not returned. In this respect,
+// ReadAt is stricter than Read.
+//
+// Even if ReadAt returns n < len(p), it may use all of p as scratch
+// space during the call. If some data is available but not len(p) bytes,
+// ReadAt blocks until either all the data is available or an error occurs.
+// In this respect ReadAt is different from Read.
//
-// 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.
+// If the n = len(p) bytes returned by ReadAt are at the end of the
+// input source, ReadAt may return either err == os.EOF or err == nil.
//
-// If ReadAt is reading from an data stream with a seek offset,
+// If ReadAt is reading from an input source with a seek offset,
// ReadAt should not affect nor be affected by the underlying
// seek offset.
type ReaderAt interface {
@@ -162,6 +176,18 @@ type ByteReader interface {
ReadByte() (c byte, err os.Error)
}
+// ByteScanner is the interface that adds the UnreadByte method to the
+// basic ReadByte method.
+//
+// UnreadByte causes the next call to ReadByte to return the same byte
+// as the previous call to ReadByte.
+// It may be an error to call UnreadByte twice without an intervening
+// call to ReadByte.
+type ByteScanner interface {
+ ByteReader
+ UnreadByte() os.Error
+}
+
// RuneReader is the interface that wraps the ReadRune method.
//
// ReadRune reads a single UTF-8 encoded Unicode character
@@ -171,8 +197,28 @@ type RuneReader interface {
ReadRune() (rune int, size int, err os.Error)
}
+// RuneScanner is the interface that adds the UnreadRune method to the
+// basic ReadRune method.
+//
+// UnreadRune causes the next call to ReadRune to return the same rune
+// as the previous call to ReadRune.
+// It may be an error to call UnreadRune twice without an intervening
+// call to ReadRune.
+type RuneScanner interface {
+ RuneReader
+ UnreadRune() os.Error
+}
+
+// stringWriter is the interface that wraps the WriteString method.
+type stringWriter interface {
+ WriteString(s string) (n int, 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) {
+ if sw, ok := w.(stringWriter); ok {
+ return sw.WriteString(s)
+ }
return w.Write([]byte(s))
}
@@ -211,7 +257,10 @@ func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
}
// Copyn copies n bytes (or until an error) from src to dst.
-// It returns the number of bytes copied and the error, if any.
+// It returns the number of bytes copied and the earliest
+// error encountered while copying. Because Read can
+// return the full amount requested as well as an error
+// (including os.EOF), so can Copyn.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
@@ -257,7 +306,11 @@ func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
// Copy copies from src to dst until either EOF is reached
// on src or an error occurs. It returns the number of bytes
-// copied and the error, if any.
+// copied and the first error encountered while copying, if any.
+//
+// A successful Copy returns err == nil, not err == os.EOF.
+// Because Copy is defined to read from src until EOF, it does
+// not treat an EOF from Read as an error to be reported.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
@@ -303,22 +356,26 @@ func Copy(dst Writer, src Reader) (written int64, err os.Error) {
// 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
+// The underlying implementation is a *LimitedReader.
+func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }
+
+// A LimitedReader reads from R but limits the amount of
+// data returned to just N bytes. Each call to Read
+// updates N to reflect the new amount remaining.
+type LimitedReader struct {
+ R Reader // underlying reader
+ N int64 // max bytes remaining
}
-func (l *limitedReader) Read(p []byte) (n int, err os.Error) {
- if l.n <= 0 {
+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]
+ if int64(len(p)) > l.N {
+ p = p[0:l.N]
}
- n, err = l.r.Read(p)
- l.n -= int64(n)
+ n, err = l.R.Read(p)
+ l.N -= int64(n)
return
}
diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go
index 5f1eecaabed..fffa1320f59 100644
--- a/libgo/go/io/ioutil/ioutil.go
+++ b/libgo/go/io/ioutil/ioutil.go
@@ -63,7 +63,7 @@ func WriteFile(filename string, data []byte, perm uint32) os.Error {
return err
}
-// A dirList implements sort.Interface.
+// A fileInfoList implements sort.Interface.
type fileInfoList []*os.FileInfo
func (f fileInfoList) Len() int { return len(f) }
@@ -108,6 +108,23 @@ func (devNull) Write(p []byte) (int, os.Error) {
return len(p), nil
}
+var blackHole = make([]byte, 8192)
+
+func (devNull) ReadFrom(r io.Reader) (n int64, err os.Error) {
+ readSize := 0
+ for {
+ readSize, err = r.Read(blackHole)
+ n += int64(readSize)
+ if err != nil {
+ if err == os.EOF {
+ return n, nil
+ }
+ return
+ }
+ }
+ panic("unreachable")
+}
+
// Discard is an io.Writer on which all Write calls succeed
// without doing anything.
var Discard io.Writer = devNull(0)
diff --git a/libgo/go/io/ioutil/ioutil_test.go b/libgo/go/io/ioutil/ioutil_test.go
index 150ee6d6328..55e4b2c2bc8 100644
--- a/libgo/go/io/ioutil/ioutil_test.go
+++ b/libgo/go/io/ioutil/ioutil_test.go
@@ -59,7 +59,6 @@ func TestWriteFile(t *testing.T) {
os.Remove(filename) // ignore error
}
-
func TestReadDir(t *testing.T) {
dirname := "rumpelstilzchen"
_, err := ReadDir(dirname)
diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go
index 3ecb7c75d99..1b3589ddeba 100644
--- a/libgo/go/io/multi_test.go
+++ b/libgo/go/io/multi_test.go
@@ -20,8 +20,9 @@ func TestMultiReader(t *testing.T) {
nread := 0
withFooBar := func(tests func()) {
r1 := strings.NewReader("foo ")
- r2 := strings.NewReader("bar")
- mr = MultiReader(r1, r2)
+ r2 := strings.NewReader("")
+ r3 := strings.NewReader("bar")
+ mr = MultiReader(r1, r2, r3)
buf = make([]byte, 20)
tests()
}
diff --git a/libgo/go/json/decode.go b/libgo/go/json/decode.go
index e78b60ccb54..4f6562bd552 100644
--- a/libgo/go/json/decode.go
+++ b/libgo/go/json/decode.go
@@ -8,7 +8,6 @@
package json
import (
- "container/vector"
"encoding/base64"
"os"
"reflect"
@@ -71,7 +70,6 @@ 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 {
@@ -253,6 +251,12 @@ func (d *decodeState) value(v reflect.Value) {
// 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) {
+ // If v is a named type and is addressable,
+ // start with its address, so that if the type has pointer methods,
+ // we find them.
+ if v.Kind() != reflect.Ptr && v.Type().Name() != "" && v.CanAddr() {
+ v = v.Addr()
+ }
for {
var isUnmarshaler bool
if v.Type().NumMethod() > 0 {
@@ -482,7 +486,7 @@ func (d *decodeState) object(v reflect.Value) {
if isValidTag(key) {
for i := 0; i < sv.NumField(); i++ {
f = st.Field(i)
- if f.Tag == key {
+ if f.Tag.Get("json") == key {
ok = true
break
}
@@ -670,7 +674,7 @@ func (d *decodeState) valueInterface() interface{} {
// arrayInterface is like array but returns []interface{}.
func (d *decodeState) arrayInterface() []interface{} {
- var v vector.Vector
+ var v []interface{}
for {
// Look ahead for ] - can only happen on first iteration.
op := d.scanWhile(scanSkipSpace)
@@ -682,7 +686,7 @@ func (d *decodeState) arrayInterface() []interface{} {
d.off--
d.scan.undo(op)
- v.Push(d.valueInterface())
+ v = append(v, d.valueInterface())
// Next token must be , or ].
op = d.scanWhile(scanSkipSpace)
@@ -742,7 +746,6 @@ func (d *decodeState) objectInterface() map[string]interface{} {
return m
}
-
// literalInterface is like literal but returns an interface value.
func (d *decodeState) literalInterface() interface{} {
// All bytes inside literal return scanContinue op code.
diff --git a/libgo/go/json/decode_test.go b/libgo/go/json/decode_test.go
index bf8bf10bf89..a855d604866 100644
--- a/libgo/go/json/decode_test.go
+++ b/libgo/go/json/decode_test.go
@@ -34,18 +34,19 @@ func (u *unmarshaler) UnmarshalJSON(b []byte) os.Error {
return nil
}
+type ustruct struct {
+ M unmarshaler
+}
+
var (
um0, um1 unmarshaler // target2 of unmarshaling
ump = &um1
umtrue = unmarshaler{true}
+ umslice = []unmarshaler{unmarshaler{true}}
+ umslicep = new([]unmarshaler)
+ umstruct = ustruct{unmarshaler{true}}
)
-type badTag struct {
- X string
- Y string "y"
- Z string "@#*%(#@"
-}
-
type unmarshalTest struct {
in string
ptr interface{}
@@ -67,9 +68,6 @@ var unmarshalTests = []unmarshalTest{
{`{"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)}},
- // skip invalid tags
- {`{"X":"a", "y":"b", "Z":"c"}`, new(badTag), badTag{"a", "b", "c"}, nil},
-
// syntax errors
{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
@@ -86,6 +84,9 @@ var unmarshalTests = []unmarshalTest{
// 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},
+ {`[{"T":false}]`, &umslice, umslice, nil},
+ {`[{"T":false}]`, &umslicep, &umslice, nil},
+ {`{"M":{"T":false}}`, &umstruct, umstruct, nil},
}
func TestMarshal(t *testing.T) {
@@ -149,7 +150,6 @@ func TestUnmarshal(t *testing.T) {
println(string(data))
data, _ = Marshal(tt.out)
println(string(data))
- return
continue
}
}
@@ -217,6 +217,18 @@ func TestUnmarshalPtrPtr(t *testing.T) {
}
}
+func TestEscape(t *testing.T) {
+ const input = `"foobar"<html>`
+ const expected = `"\"foobar\"\u003chtml\u003e"`
+ b, err := Marshal(input)
+ if err != nil {
+ t.Fatalf("Marshal error: %v", err)
+ }
+ if s := string(b); s != expected {
+ t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected)
+ }
+}
+
func TestHTMLEscape(t *testing.T) {
b, err := MarshalForHTML("foobarbaz<>&quux")
if err != nil {
@@ -250,7 +262,7 @@ type All struct {
Float32 float32
Float64 float64
- Foo string "bar"
+ Foo string `json:"bar"`
PBool *bool
PInt *int
diff --git a/libgo/go/json/encode.go b/libgo/go/json/encode.go
index ec0a14a6a4d..3e593fec15f 100644
--- a/libgo/go/json/encode.go
+++ b/libgo/go/json/encode.go
@@ -14,6 +14,7 @@ import (
"runtime"
"sort"
"strconv"
+ "strings"
"unicode"
"utf8"
)
@@ -36,11 +37,30 @@ import (
// Array and slice values encode as JSON arrays, except that
// []byte encodes as a base64-encoded string.
//
-// 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. If the struct field has a non-empty tag consisting
-// of only Unicode letters, digits, and underscores, that tag will be used
-// as the name instead. Only exported fields will be encoded.
+// Struct values encode as JSON objects. Each exported struct field
+// becomes a member of the object unless the field is empty and its tag
+// specifies the "omitempty" option. The empty values are false, 0, any
+// nil pointer or interface value, and any array, slice, map, or string of
+// length zero. The object's default key string is the struct field name
+// but can be specified in the struct field's tag value. The "json" key in
+// struct field's tag value is the key name, followed by an optional comma
+// and options. Examples:
+//
+// // Specifies that Field appears in JSON as key "myName"
+// Field int `json:"myName"`
+//
+// // Specifies that Field appears in JSON as key "myName" and
+// // the field is omitted from the object if its value is empty,
+// // as defined above.
+// Field int `json:"myName,omitempty"`
+//
+// // Field appears in JSON as key "Field" (the default), but
+// // the field is skipped if empty.
+// // Note the leading comma.
+// Field int `json:",omitempty"`
+//
+// The key name will be used if it's a non-empty string consisting of
+// only Unicode letters, digits, dollar signs, hyphens, and underscores.
//
// Map values encode as JSON objects.
// The map's key type must be string; the object keys are used directly
@@ -182,6 +202,24 @@ func (e *encodeState) error(err os.Error) {
var byteSliceType = reflect.TypeOf([]byte(nil))
+func isEmptyValue(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ return v.IsNil()
+ }
+ return false
+}
+
func (e *encodeState) reflectValue(v reflect.Value) {
if !v.IsValid() {
e.WriteString("null")
@@ -231,18 +269,30 @@ func (e *encodeState) reflectValue(v reflect.Value) {
if f.PkgPath != "" {
continue
}
+ tag, omitEmpty := f.Name, false
+ if tv := f.Tag.Get("json"); tv != "" {
+ ss := strings.SplitN(tv, ",", 2)
+ if isValidTag(ss[0]) {
+ tag = ss[0]
+ }
+ if len(ss) > 1 {
+ // Currently the only option is omitempty,
+ // so parsing is trivial.
+ omitEmpty = ss[1] == "omitempty"
+ }
+ }
+ fieldValue := v.Field(i)
+ if omitEmpty && isEmptyValue(fieldValue) {
+ continue
+ }
if first {
first = false
} else {
e.WriteByte(',')
}
- if isValidTag(f.Tag) {
- e.string(f.Tag)
- } else {
- e.string(f.Name)
- }
+ e.string(tag)
e.WriteByte(':')
- e.reflectValue(v.Field(i))
+ e.reflectValue(fieldValue)
}
e.WriteByte('}')
@@ -314,7 +364,7 @@ func isValidTag(s string) bool {
return false
}
for _, c := range s {
- if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+ if c != '$' && c != '-' && c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
return false
}
}
@@ -335,17 +385,28 @@ func (e *encodeState) string(s string) {
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
- if 0x20 <= b && b != '\\' && b != '"' {
+ if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' {
i++
continue
}
if start < i {
e.WriteString(s[start:i])
}
- if b == '\\' || b == '"' {
+ switch b {
+ case '\\', '"':
e.WriteByte('\\')
e.WriteByte(b)
- } else {
+ case '\n':
+ e.WriteByte('\\')
+ e.WriteByte('n')
+ case '\r':
+ e.WriteByte('\\')
+ e.WriteByte('r')
+ default:
+ // This encodes bytes < 0x20 except for \n and \r,
+ // as well as < and >. The latter are escaped because they
+ // can lead to security holes when user-controlled strings
+ // are rendered into JSON and served to some browsers.
e.WriteString(`\u00`)
e.WriteByte(hex[b>>4])
e.WriteByte(hex[b&0xF])
diff --git a/libgo/go/json/encode_test.go b/libgo/go/json/encode_test.go
new file mode 100644
index 00000000000..0e4b637703d
--- /dev/null
+++ b/libgo/go/json/encode_test.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.
+
+package json
+
+import (
+ "testing"
+)
+
+type Optionals struct {
+ Sr string `json:"sr"`
+ So string `json:"so,omitempty"`
+
+ Ir int `json:"omitempty"` // actually named omitempty, not an option
+ Io int `json:"io,omitempty"`
+
+ Slr []string `json:"slr,random"`
+ Slo []string `json:"slo,omitempty"`
+
+ Mr map[string]interface{} `json:"mr"`
+ Mo map[string]interface{} `json:",omitempty"`
+}
+
+var optionalsExpected = `{
+ "sr": "",
+ "omitempty": 0,
+ "slr": [],
+ "mr": {}
+}`
+
+func TestOmitEmpty(t *testing.T) {
+ var o Optionals
+ o.Mr = map[string]interface{}{}
+ o.Mo = map[string]interface{}{}
+
+ got, err := MarshalIndent(&o, "", " ")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got := string(got); got != optionalsExpected {
+ t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
+ }
+}
diff --git a/libgo/go/json/scanner_test.go b/libgo/go/json/scanner_test.go
index df87c716aff..023e7c81ee4 100644
--- a/libgo/go/json/scanner_test.go
+++ b/libgo/go/json/scanner_test.go
@@ -255,7 +255,7 @@ func genArray(n int) []interface{} {
if n > 0 && f == 0 {
f = 1
}
- x := make([]interface{}, int(f))
+ x := make([]interface{}, f)
for i := range x {
x[i] = genValue(((i+1)*n)/f - (i*n)/f)
}
diff --git a/libgo/go/json/tagkey_test.go b/libgo/go/json/tagkey_test.go
new file mode 100644
index 00000000000..31fe2be3621
--- /dev/null
+++ b/libgo/go/json/tagkey_test.go
@@ -0,0 +1,95 @@
+// 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 json
+
+import (
+ "testing"
+)
+
+type basicLatin2xTag struct {
+ V string `json:"$-"`
+}
+
+type basicLatin3xTag struct {
+ V string `json:"0123456789"`
+}
+
+type basicLatin4xTag struct {
+ V string `json:"ABCDEFGHIJKLMO"`
+}
+
+type basicLatin5xTag struct {
+ V string `json:"PQRSTUVWXYZ_"`
+}
+
+type basicLatin6xTag struct {
+ V string `json:"abcdefghijklmno"`
+}
+
+type basicLatin7xTag struct {
+ V string `json:"pqrstuvwxyz"`
+}
+
+type miscPlaneTag struct {
+ V string `json:"色は匂へど"`
+}
+
+type emptyTag struct {
+ W string
+}
+
+type misnamedTag struct {
+ X string `jsom:"Misnamed"`
+}
+
+type badFormatTag struct {
+ Y string `:"BadFormat"`
+}
+
+type badCodeTag struct {
+ Z string `json:" !\"#%&'()*+,./"`
+}
+
+var structTagObjectKeyTests = []struct {
+ raw interface{}
+ value string
+ key string
+}{
+ {basicLatin2xTag{"2x"}, "2x", "$-"},
+ {basicLatin3xTag{"3x"}, "3x", "0123456789"},
+ {basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
+ {basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
+ {basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
+ {basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
+ {miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
+ {emptyTag{"Pour Moi"}, "Pour Moi", "W"},
+ {misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
+ {badFormatTag{"Orfevre"}, "Orfevre", "Y"},
+ {badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
+}
+
+func TestStructTagObjectKey(t *testing.T) {
+ for _, tt := range structTagObjectKeyTests {
+ b, err := Marshal(tt.raw)
+ if err != nil {
+ t.Fatalf("Marshal(%#q) failed: %v", tt.raw, err)
+ }
+ var f interface{}
+ err = Unmarshal(b, &f)
+ if err != nil {
+ t.Fatalf("Unmarshal(%#q) failed: %v", b, err)
+ }
+ for i, v := range f.(map[string]interface{}) {
+ switch i {
+ case tt.key:
+ if s, ok := v.(string); !ok || s != tt.value {
+ t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
+ }
+ default:
+ t.Fatalf("Unexpected key: %#q", i)
+ }
+ }
+ }
+}
diff --git a/libgo/go/log/log.go b/libgo/go/log/log.go
index 00bce6a17dc..ec097434bbb 100644
--- a/libgo/go/log/log.go
+++ b/libgo/go/log/log.go
@@ -41,9 +41,9 @@ const (
// 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; protects the following fields
prefix string // prefix to write at beginning of each line
flag int // properties
- mu sync.Mutex // ensures atomic writes; protects the following fields
out io.Writer // destination for output
buf bytes.Buffer // for accumulating text to write
}
@@ -134,19 +134,21 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int
// paths it will be 2.
func (l *Logger) Output(calldepth int, s string) os.Error {
now := time.Nanoseconds() // get this early.
- // get caller info (if required) before locking - it's expensive.
var file string
var line int
+ l.mu.Lock()
+ defer l.mu.Unlock()
if l.flag&(Lshortfile|Llongfile) != 0 {
+ // release lock while getting caller info - it's expensive.
+ l.mu.Unlock()
var ok bool
_, file, line, ok = runtime.Caller(calldepth)
if !ok {
file = "???"
line = 0
}
+ l.mu.Lock()
}
- l.mu.Lock()
- defer l.mu.Unlock()
l.buf.Reset()
l.formatHeader(&l.buf, now, file, line)
l.buf.WriteString(s)
@@ -212,26 +214,36 @@ func (l *Logger) Panicln(v ...interface{}) {
// Flags returns the output flags for the logger.
func (l *Logger) Flags() int {
+ l.mu.Lock()
+ defer l.mu.Unlock()
return l.flag
}
// SetFlags sets the output flags for the logger.
func (l *Logger) SetFlags(flag int) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
l.flag = flag
}
// Prefix returns the output prefix for the logger.
func (l *Logger) Prefix() string {
+ l.mu.Lock()
+ defer l.mu.Unlock()
return l.prefix
}
// SetPrefix sets the output prefix for the logger.
func (l *Logger) SetPrefix(prefix string) {
+ l.mu.Lock()
+ defer l.mu.Unlock()
l.prefix = prefix
}
// SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) {
+ std.mu.Lock()
+ defer std.mu.Unlock()
std.out = w
}
diff --git a/libgo/go/mail/message.go b/libgo/go/mail/message.go
new file mode 100644
index 00000000000..e227d17d6fa
--- /dev/null
+++ b/libgo/go/mail/message.go
@@ -0,0 +1,524 @@
+// 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 mail implements parsing of mail messages.
+
+For the most part, this package follows the syntax as specified by RFC 5322.
+Notable divergences:
+ * Obsolete address formats are not parsed, including addresses with
+ embedded route information.
+ * Group addresses are not parsed.
+ * The full range of spacing (the CFWS syntax element) is not supported,
+ such as breaking addresses across lines.
+*/
+package mail
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/textproto"
+ "os"
+ "strconv"
+ "strings"
+ "time"
+)
+
+var debug = debugT(false)
+
+type debugT bool
+
+func (d debugT) Printf(format string, args ...interface{}) {
+ if d {
+ log.Printf(format, args...)
+ }
+}
+
+// A Message represents a parsed mail message.
+type Message struct {
+ Header Header
+ Body io.Reader
+}
+
+// ReadMessage reads a message from r.
+// The headers are parsed, and the body of the message will be reading from r.
+func ReadMessage(r io.Reader) (msg *Message, err os.Error) {
+ tp := textproto.NewReader(bufio.NewReader(r))
+
+ hdr, err := tp.ReadMIMEHeader()
+ if err != nil {
+ return nil, err
+ }
+
+ return &Message{
+ Header: Header(hdr),
+ Body: tp.R,
+ }, nil
+}
+
+// Layouts suitable for passing to time.Parse.
+// These are tried in order.
+var dateLayouts []string
+
+func init() {
+ // Generate layouts based on RFC 5322, section 3.3.
+
+ dows := [...]string{"", "Mon, "} // day-of-week
+ days := [...]string{"2", "02"} // day = 1*2DIGIT
+ years := [...]string{"2006", "06"} // year = 4*DIGIT / 2*DIGIT
+ seconds := [...]string{":05", ""} // second
+ zones := [...]string{"-0700", "MST"} // zone = (("+" / "-") 4DIGIT) / "GMT" / ...
+
+ for _, dow := range dows {
+ for _, day := range days {
+ for _, year := range years {
+ for _, second := range seconds {
+ for _, zone := range zones {
+ s := dow + day + " Jan " + year + " 15:04" + second + " " + zone
+ dateLayouts = append(dateLayouts, s)
+ }
+ }
+ }
+ }
+ }
+}
+
+func parseDate(date string) (*time.Time, os.Error) {
+ for _, layout := range dateLayouts {
+ t, err := time.Parse(layout, date)
+ if err == nil {
+ return t, nil
+ }
+ }
+ return nil, os.NewError("mail: header could not be parsed")
+}
+
+// A Header represents the key-value pairs in a mail message header.
+type Header map[string][]string
+
+// Get gets the first value associated with the given key.
+// If there are no values associated with the key, Get returns "".
+func (h Header) Get(key string) string {
+ return textproto.MIMEHeader(h).Get(key)
+}
+
+var ErrHeaderNotPresent = os.NewError("mail: header not in message")
+
+// Date parses the Date header field.
+func (h Header) Date() (*time.Time, os.Error) {
+ hdr := h.Get("Date")
+ if hdr == "" {
+ return nil, ErrHeaderNotPresent
+ }
+ return parseDate(hdr)
+}
+
+// AddressList parses the named header field as a list of addresses.
+func (h Header) AddressList(key string) ([]*Address, os.Error) {
+ hdr := h.Get(key)
+ if hdr == "" {
+ return nil, ErrHeaderNotPresent
+ }
+ return newAddrParser(hdr).parseAddressList()
+}
+
+// Address represents a single mail address.
+// An address such as "Barry Gibbs <bg@example.com>" is represented
+// as Address{Name: "Barry Gibbs", Address: "bg@example.com"}.
+type Address struct {
+ Name string // Proper name; may be empty.
+ Address string // user@domain
+}
+
+// String formats the address as a valid RFC 5322 address.
+// If the address's name contains non-ASCII characters
+// the name will be rendered according to RFC 2047.
+func (a *Address) String() string {
+ s := "<" + a.Address + ">"
+ if a.Name == "" {
+ return s
+ }
+ // If every character is printable ASCII, quoting is simple.
+ allPrintable := true
+ for i := 0; i < len(a.Name); i++ {
+ if !isVchar(a.Name[i]) {
+ allPrintable = false
+ break
+ }
+ }
+ if allPrintable {
+ b := bytes.NewBufferString(`"`)
+ for i := 0; i < len(a.Name); i++ {
+ if !isQtext(a.Name[i]) {
+ b.WriteByte('\\')
+ }
+ b.WriteByte(a.Name[i])
+ }
+ b.WriteString(`" `)
+ b.WriteString(s)
+ return b.String()
+ }
+
+ // UTF-8 "Q" encoding
+ b := bytes.NewBufferString("=?utf-8?q?")
+ for i := 0; i < len(a.Name); i++ {
+ switch c := a.Name[i]; {
+ case c == ' ':
+ b.WriteByte('_')
+ case isVchar(c) && c != '=' && c != '?' && c != '_':
+ b.WriteByte(c)
+ default:
+ fmt.Fprintf(b, "=%02X", c)
+ }
+ }
+ b.WriteString("?= ")
+ b.WriteString(s)
+ return b.String()
+}
+
+type addrParser []byte
+
+func newAddrParser(s string) *addrParser {
+ p := addrParser([]byte(s))
+ return &p
+}
+
+func (p *addrParser) parseAddressList() ([]*Address, os.Error) {
+ var list []*Address
+ for {
+ p.skipSpace()
+ addr, err := p.parseAddress()
+ if err != nil {
+ return nil, err
+ }
+ list = append(list, addr)
+
+ p.skipSpace()
+ if p.empty() {
+ break
+ }
+ if !p.consume(',') {
+ return nil, os.NewError("mail: expected comma")
+ }
+ }
+ return list, nil
+}
+
+// parseAddress parses a single RFC 5322 address at the start of p.
+func (p *addrParser) parseAddress() (addr *Address, err os.Error) {
+ debug.Printf("parseAddress: %q", *p)
+ p.skipSpace()
+ if p.empty() {
+ return nil, os.NewError("mail: no address")
+ }
+
+ // address = name-addr / addr-spec
+ // TODO(dsymonds): Support parsing group address.
+
+ // addr-spec has a more restricted grammar than name-addr,
+ // so try parsing it first, and fallback to name-addr.
+ // TODO(dsymonds): Is this really correct?
+ spec, err := p.consumeAddrSpec()
+ if err == nil {
+ return &Address{
+ Address: spec,
+ }, err
+ }
+ debug.Printf("parseAddress: not an addr-spec: %v", err)
+ debug.Printf("parseAddress: state is now %q", *p)
+
+ // display-name
+ var displayName string
+ if p.peek() != '<' {
+ displayName, err = p.consumePhrase()
+ if err != nil {
+ return nil, err
+ }
+ }
+ debug.Printf("parseAddress: displayName=%q", displayName)
+
+ // angle-addr = "<" addr-spec ">"
+ p.skipSpace()
+ if !p.consume('<') {
+ return nil, os.NewError("mail: no angle-addr")
+ }
+ spec, err = p.consumeAddrSpec()
+ if err != nil {
+ return nil, err
+ }
+ if !p.consume('>') {
+ return nil, os.NewError("mail: unclosed angle-addr")
+ }
+ debug.Printf("parseAddress: spec=%q", spec)
+
+ return &Address{
+ Name: displayName,
+ Address: spec,
+ }, nil
+}
+
+// consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p.
+func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
+ debug.Printf("consumeAddrSpec: %q", *p)
+
+ orig := *p
+ defer func() {
+ if err != nil {
+ *p = orig
+ }
+ }()
+
+ // local-part = dot-atom / quoted-string
+ var localPart string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.NewError("mail: no addr-spec")
+ }
+ if p.peek() == '"' {
+ // quoted-string
+ debug.Printf("consumeAddrSpec: parsing quoted-string")
+ localPart, err = p.consumeQuotedString()
+ } else {
+ // dot-atom
+ debug.Printf("consumeAddrSpec: parsing dot-atom")
+ localPart, err = p.consumeAtom(true)
+ }
+ if err != nil {
+ debug.Printf("consumeAddrSpec: failed: %v", err)
+ return "", err
+ }
+
+ if !p.consume('@') {
+ return "", os.NewError("mail: missing @ in addr-spec")
+ }
+
+ // domain = dot-atom / domain-literal
+ var domain string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.NewError("mail: no domain in addr-spec")
+ }
+ // TODO(dsymonds): Handle domain-literal
+ domain, err = p.consumeAtom(true)
+ if err != nil {
+ return "", err
+ }
+
+ return localPart + "@" + domain, nil
+}
+
+// consumePhrase parses the RFC 5322 phrase at the start of p.
+func (p *addrParser) consumePhrase() (phrase string, err os.Error) {
+ debug.Printf("consumePhrase: [%s]", *p)
+ // phrase = 1*word
+ var words []string
+ for {
+ // word = atom / quoted-string
+ var word string
+ p.skipSpace()
+ if p.empty() {
+ return "", os.NewError("mail: missing phrase")
+ }
+ if p.peek() == '"' {
+ // quoted-string
+ word, err = p.consumeQuotedString()
+ } else {
+ // atom
+ word, err = p.consumeAtom(false)
+ }
+
+ // RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s.
+ if err == nil && strings.HasPrefix(word, "=?") && strings.HasSuffix(word, "?=") && strings.Count(word, "?") == 4 {
+ word, err = decodeRFC2047Word(word)
+ }
+
+ if err != nil {
+ break
+ }
+ debug.Printf("consumePhrase: consumed %q", word)
+ words = append(words, word)
+ }
+ // Ignore any error if we got at least one word.
+ if err != nil && len(words) == 0 {
+ debug.Printf("consumePhrase: hit err: %v", err)
+ return "", os.NewError("mail: missing word in phrase")
+ }
+ phrase = strings.Join(words, " ")
+ return phrase, nil
+}
+
+// consumeQuotedString parses the quoted string at the start of p.
+func (p *addrParser) consumeQuotedString() (qs string, err os.Error) {
+ // Assume first byte is '"'.
+ i := 1
+ qsb := make([]byte, 0, 10)
+Loop:
+ for {
+ if i >= p.len() {
+ return "", os.NewError("mail: unclosed quoted-string")
+ }
+ switch c := (*p)[i]; {
+ case c == '"':
+ break Loop
+ case c == '\\':
+ if i+1 == p.len() {
+ return "", os.NewError("mail: unclosed quoted-string")
+ }
+ qsb = append(qsb, (*p)[i+1])
+ i += 2
+ case isQtext(c), c == ' ' || c == '\t':
+ // qtext (printable US-ASCII excluding " and \), or
+ // FWS (almost; we're ignoring CRLF)
+ qsb = append(qsb, c)
+ i++
+ default:
+ return "", fmt.Errorf("mail: bad character in quoted-string: %q", c)
+ }
+ }
+ *p = (*p)[i+1:]
+ return string(qsb), nil
+}
+
+// consumeAtom parses an RFC 5322 atom at the start of p.
+// If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
+func (p *addrParser) consumeAtom(dot bool) (atom string, err os.Error) {
+ if !isAtext(p.peek(), false) {
+ return "", os.NewError("mail: invalid string")
+ }
+ i := 1
+ for ; i < p.len() && isAtext((*p)[i], dot); i++ {
+ }
+ // TODO(dsymonds): Remove the []byte() conversion here when 6g doesn't need it.
+ atom, *p = string([]byte((*p)[:i])), (*p)[i:]
+ return atom, nil
+}
+
+func (p *addrParser) consume(c byte) bool {
+ if p.empty() || p.peek() != c {
+ return false
+ }
+ *p = (*p)[1:]
+ return true
+}
+
+// skipSpace skips the leading space and tab characters.
+func (p *addrParser) skipSpace() {
+ *p = bytes.TrimLeft(*p, " \t")
+}
+
+func (p *addrParser) peek() byte {
+ return (*p)[0]
+}
+
+func (p *addrParser) empty() bool {
+ return p.len() == 0
+}
+
+func (p *addrParser) len() int {
+ return len(*p)
+}
+
+func decodeRFC2047Word(s string) (string, os.Error) {
+ fields := strings.Split(s, "?")
+ if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
+ return "", os.NewError("mail: address not RFC 2047 encoded")
+ }
+ charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
+ if charset != "iso-8859-1" && charset != "utf-8" {
+ return "", fmt.Errorf("mail: charset not supported: %q", charset)
+ }
+
+ in := bytes.NewBufferString(fields[3])
+ var r io.Reader
+ switch enc {
+ case "b":
+ r = base64.NewDecoder(base64.StdEncoding, in)
+ case "q":
+ r = qDecoder{r: in}
+ default:
+ return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
+ }
+
+ dec, err := ioutil.ReadAll(r)
+ if err != nil {
+ return "", err
+ }
+
+ switch charset {
+ case "iso-8859-1":
+ b := new(bytes.Buffer)
+ for _, c := range dec {
+ b.WriteRune(int(c))
+ }
+ return b.String(), nil
+ case "utf-8":
+ return string(dec), nil
+ }
+ panic("unreachable")
+}
+
+type qDecoder struct {
+ r io.Reader
+ scratch [2]byte
+}
+
+func (qd qDecoder) Read(p []byte) (n int, err os.Error) {
+ // This method writes at most one byte into p.
+ if len(p) == 0 {
+ return 0, nil
+ }
+ if _, err := qd.r.Read(qd.scratch[:1]); err != nil {
+ return 0, err
+ }
+ switch c := qd.scratch[0]; {
+ case c == '=':
+ if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil {
+ return 0, err
+ }
+ x, err := strconv.Btoi64(string(qd.scratch[:2]), 16)
+ if err != nil {
+ return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2])
+ }
+ p[0] = byte(x)
+ case c == '_':
+ p[0] = ' '
+ default:
+ p[0] = c
+ }
+ return 1, nil
+}
+
+var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "abcdefghijklmnopqrstuvwxyz" +
+ "0123456789" +
+ "!#$%&'*+-/=?^_`{|}~")
+
+// isAtext returns true if c is an RFC 5322 atext character.
+// If dot is true, period is included.
+func isAtext(c byte, dot bool) bool {
+ if dot && c == '.' {
+ return true
+ }
+ return bytes.IndexByte(atextChars, c) >= 0
+}
+
+// isQtext returns true if c is an RFC 5322 qtest character.
+func isQtext(c byte) bool {
+ // Printable US-ASCII, excluding backslash or quote.
+ if c == '\\' || c == '"' {
+ return false
+ }
+ return '!' <= c && c <= '~'
+}
+
+// isVchar returns true if c is an RFC 5322 VCHAR character.
+func isVchar(c byte) bool {
+ // Visible (printing) characters.
+ return '!' <= c && c <= '~'
+}
diff --git a/libgo/go/mail/message_test.go b/libgo/go/mail/message_test.go
new file mode 100644
index 00000000000..e1bcc89ee5f
--- /dev/null
+++ b/libgo/go/mail/message_test.go
@@ -0,0 +1,278 @@
+// 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 mail
+
+import (
+ "bytes"
+ "io/ioutil"
+ "reflect"
+ "testing"
+ "time"
+)
+
+var parseTests = []struct {
+ in string
+ header Header
+ body string
+}{
+ {
+ // RFC 5322, Appendix A.1.1
+ in: `From: John Doe <jdoe@machine.example>
+To: Mary Smith <mary@example.net>
+Subject: Saying Hello
+Date: Fri, 21 Nov 1997 09:55:06 -0600
+Message-ID: <1234@local.machine.example>
+
+This is a message just to say hello.
+So, "Hello".
+`,
+ header: Header{
+ "From": []string{"John Doe <jdoe@machine.example>"},
+ "To": []string{"Mary Smith <mary@example.net>"},
+ "Subject": []string{"Saying Hello"},
+ "Date": []string{"Fri, 21 Nov 1997 09:55:06 -0600"},
+ "Message-Id": []string{"<1234@local.machine.example>"},
+ },
+ body: "This is a message just to say hello.\nSo, \"Hello\".\n",
+ },
+}
+
+func TestParsing(t *testing.T) {
+ for i, test := range parseTests {
+ msg, err := ReadMessage(bytes.NewBuffer([]byte(test.in)))
+ if err != nil {
+ t.Errorf("test #%d: Failed parsing message: %v", i, err)
+ continue
+ }
+ if !headerEq(msg.Header, test.header) {
+ t.Errorf("test #%d: Incorrectly parsed message header.\nGot:\n%+v\nWant:\n%+v",
+ i, msg.Header, test.header)
+ }
+ body, err := ioutil.ReadAll(msg.Body)
+ if err != nil {
+ t.Errorf("test #%d: Failed reading body: %v", i, err)
+ continue
+ }
+ bodyStr := string(body)
+ if bodyStr != test.body {
+ t.Errorf("test #%d: Incorrectly parsed message body.\nGot:\n%+v\nWant:\n%+v",
+ i, bodyStr, test.body)
+ }
+ }
+}
+
+func headerEq(a, b Header) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for k, as := range a {
+ bs, ok := b[k]
+ if !ok {
+ return false
+ }
+ if !reflect.DeepEqual(as, bs) {
+ return false
+ }
+ }
+ return true
+}
+
+func TestDateParsing(t *testing.T) {
+ tests := []struct {
+ dateStr string
+ exp *time.Time
+ }{
+ // RFC 5322, Appendix A.1.1
+ {
+ "Fri, 21 Nov 1997 09:55:06 -0600",
+ &time.Time{
+ Year: 1997,
+ Month: 11,
+ Day: 21,
+ Hour: 9,
+ Minute: 55,
+ Second: 6,
+ Weekday: 5, // Fri
+ ZoneOffset: -6 * 60 * 60,
+ },
+ },
+ // RFC5322, Appendix A.6.2
+ // Obsolete date.
+ {
+ "21 Nov 97 09:55:06 GMT",
+ &time.Time{
+ Year: 1997,
+ Month: 11,
+ Day: 21,
+ Hour: 9,
+ Minute: 55,
+ Second: 6,
+ Zone: "GMT",
+ },
+ },
+ }
+ for _, test := range tests {
+ hdr := Header{
+ "Date": []string{test.dateStr},
+ }
+ date, err := hdr.Date()
+ if err != nil {
+ t.Errorf("Failed parsing %q: %v", test.dateStr, err)
+ continue
+ }
+ if !reflect.DeepEqual(date, test.exp) {
+ t.Errorf("Parse of %q: got %+v, want %+v", test.dateStr, date, test.exp)
+ }
+ }
+}
+
+func TestAddressParsing(t *testing.T) {
+ tests := []struct {
+ addrsStr string
+ exp []*Address
+ }{
+ // Bare address
+ {
+ `jdoe@machine.example`,
+ []*Address{&Address{
+ Address: "jdoe@machine.example",
+ }},
+ },
+ // RFC 5322, Appendix A.1.1
+ {
+ `John Doe <jdoe@machine.example>`,
+ []*Address{&Address{
+ Name: "John Doe",
+ Address: "jdoe@machine.example",
+ }},
+ },
+ // RFC 5322, Appendix A.1.2
+ {
+ `"Joe Q. Public" <john.q.public@example.com>`,
+ []*Address{&Address{
+ Name: "Joe Q. Public",
+ Address: "john.q.public@example.com",
+ }},
+ },
+ {
+ `Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>`,
+ []*Address{
+ &Address{
+ Name: "Mary Smith",
+ Address: "mary@x.test",
+ },
+ &Address{
+ Address: "jdoe@example.org",
+ },
+ &Address{
+ Name: "Who?",
+ Address: "one@y.test",
+ },
+ },
+ },
+ {
+ `<boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>`,
+ []*Address{
+ &Address{
+ Address: "boss@nil.test",
+ },
+ &Address{
+ Name: `Giant; "Big" Box`,
+ Address: "sysservices@example.net",
+ },
+ },
+ },
+ // RFC 5322, Appendix A.1.3
+ // TODO(dsymonds): Group addresses.
+
+ // RFC 2047 "Q"-encoded ISO-8859-1 address.
+ {
+ `=?iso-8859-1?q?J=F6rg_Doe?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg Doe`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // RFC 2047 "Q"-encoded UTF-8 address.
+ {
+ `=?utf-8?q?J=C3=B6rg_Doe?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg Doe`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // RFC 2047, Section 8.
+ {
+ `=?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>`,
+ []*Address{
+ &Address{
+ Name: `André Pirard`,
+ Address: "PIRARD@vm1.ulg.ac.be",
+ },
+ },
+ },
+ // Custom example of RFC 2047 "B"-encoded ISO-8859-1 address.
+ {
+ `=?ISO-8859-1?B?SvZyZw==?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // Custom example of RFC 2047 "B"-encoded UTF-8 address.
+ {
+ `=?UTF-8?B?SsO2cmc=?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ }
+ for _, test := range tests {
+ addrs, err := newAddrParser(test.addrsStr).parseAddressList()
+ if err != nil {
+ t.Errorf("Failed parsing %q: %v", test.addrsStr, err)
+ continue
+ }
+ if !reflect.DeepEqual(addrs, test.exp) {
+ t.Errorf("Parse of %q: got %+v, want %+v", test.addrsStr, addrs, test.exp)
+ }
+ }
+}
+
+func TestAddressFormatting(t *testing.T) {
+ tests := []struct {
+ addr *Address
+ exp string
+ }{
+ {
+ &Address{Address: "bob@example.com"},
+ "<bob@example.com>",
+ },
+ {
+ &Address{Name: "Bob", Address: "bob@example.com"},
+ `"Bob" <bob@example.com>`,
+ },
+ {
+ // note the ö (o with an umlaut)
+ &Address{Name: "Böb", Address: "bob@example.com"},
+ `=?utf-8?q?B=C3=B6b?= <bob@example.com>`,
+ },
+ }
+ for _, test := range tests {
+ s := test.addr.String()
+ if s != test.exp {
+ t.Errorf("Address%+v.String() = %v, want %v", *test.addr, s, test.exp)
+ }
+ }
+}
diff --git a/libgo/go/math/acosh.go b/libgo/go/math/acosh.go
index d8067c06583..7e8740b89bd 100644
--- a/libgo/go/math/acosh.go
+++ b/libgo/go/math/acosh.go
@@ -4,7 +4,6 @@
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
diff --git a/libgo/go/math/asin.go b/libgo/go/math/asin.go
index 3bace8ff1c4..0a0b0a11cb4 100644
--- a/libgo/go/math/asin.go
+++ b/libgo/go/math/asin.go
@@ -4,7 +4,6 @@
package math
-
/*
Floating-point arcsine and arccosine.
diff --git a/libgo/go/math/asinh.go b/libgo/go/math/asinh.go
index 90dcd27ab97..c1cad563c76 100644
--- a/libgo/go/math/asinh.go
+++ b/libgo/go/math/asinh.go
@@ -4,7 +4,6 @@
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
diff --git a/libgo/go/math/atanh.go b/libgo/go/math/atanh.go
index 6aecb7b3bb3..ed38fcac665 100644
--- a/libgo/go/math/atanh.go
+++ b/libgo/go/math/atanh.go
@@ -4,7 +4,6 @@
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
diff --git a/libgo/go/math/erf.go b/libgo/go/math/erf.go
index b608999337a..6d3d9b7c537 100644
--- a/libgo/go/math/erf.go
+++ b/libgo/go/math/erf.go
@@ -4,7 +4,6 @@
package math
-
/*
Floating-point error function and complementary error function.
*/
diff --git a/libgo/go/math/exp_port.go b/libgo/go/math/exp_port.go
index 071420c24c5..618c31a5d11 100644
--- a/libgo/go/math/exp_port.go
+++ b/libgo/go/math/exp_port.go
@@ -4,7 +4,6 @@
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
diff --git a/libgo/go/math/expm1.go b/libgo/go/math/expm1.go
index 35100caa402..e9f833140b5 100644
--- a/libgo/go/math/expm1.go
+++ b/libgo/go/math/expm1.go
@@ -4,7 +4,6 @@
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
diff --git a/libgo/go/math/floor.go b/libgo/go/math/floor.go
index b22b94ad639..babbf645f5c 100644
--- a/libgo/go/math/floor.go
+++ b/libgo/go/math/floor.go
@@ -4,7 +4,6 @@
package math
-
// Floor returns the greatest integer value less than or equal to x.
//
// Special cases are:
diff --git a/libgo/go/math/fmod.go b/libgo/go/math/fmod.go
index fc57f7483fa..75c614629d4 100644
--- a/libgo/go/math/fmod.go
+++ b/libgo/go/math/fmod.go
@@ -4,7 +4,6 @@
package math
-
/*
Floating-point mod function.
*/
diff --git a/libgo/go/math/log.go b/libgo/go/math/log.go
index 39d94512d3f..a786c8ce3ab 100644
--- a/libgo/go/math/log.go
+++ b/libgo/go/math/log.go
@@ -23,7 +23,7 @@ package math
// ====================================================
//
// __ieee754_log(x)
-// Return the logrithm of x
+// Return the logarithm of x
//
// Method :
// 1. Argument Reduction: find k and f such that
diff --git a/libgo/go/math/log1p.go b/libgo/go/math/log1p.go
index e1fc275d0c3..c25d73b6641 100644
--- a/libgo/go/math/log1p.go
+++ b/libgo/go/math/log1p.go
@@ -4,7 +4,6 @@
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
diff --git a/libgo/go/math/sin.go b/libgo/go/math/sin.go
index 35220cb3e5a..8a2edd7e563 100644
--- a/libgo/go/math/sin.go
+++ b/libgo/go/math/sin.go
@@ -4,7 +4,6 @@
package math
-
/*
Floating-point sine and cosine.
diff --git a/libgo/go/math/sinh.go b/libgo/go/math/sinh.go
index 23a8719f2ca..eaf28a51cd6 100644
--- a/libgo/go/math/sinh.go
+++ b/libgo/go/math/sinh.go
@@ -4,7 +4,6 @@
package math
-
/*
Floating-point hyperbolic sine and cosine.
diff --git a/libgo/go/math/sqrt_port.go b/libgo/go/math/sqrt_port.go
index 6f35a383d11..148239bcff6 100644
--- a/libgo/go/math/sqrt_port.go
+++ b/libgo/go/math/sqrt_port.go
@@ -50,7 +50,7 @@ package math
// 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
+// With some algebraic manipulation, it is not difficult to see
// that (2) is equivalent to
// -(i+1)
// s + 2 <= y (3)
@@ -141,3 +141,7 @@ func sqrtGo(x float64) float64 {
ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
return Float64frombits(ix)
}
+
+func sqrtGoC(f float64, r *float64) {
+ *r = sqrtGo(f)
+}
diff --git a/libgo/go/math/tan.go b/libgo/go/math/tan.go
index a36ebbf449c..6d7a60ba6b2 100644
--- a/libgo/go/math/tan.go
+++ b/libgo/go/math/tan.go
@@ -4,7 +4,6 @@
package math
-
/*
Floating point tangent.
*/
diff --git a/libgo/go/math/tanh.go b/libgo/go/math/tanh.go
index 8bcf2ddac2e..f4a8a5a4d60 100644
--- a/libgo/go/math/tanh.go
+++ b/libgo/go/math/tanh.go
@@ -4,7 +4,6 @@
package math
-
/*
Floating-point hyperbolic tangent.
diff --git a/libgo/go/mime/grammar.go b/libgo/go/mime/grammar.go
index e60cbb8df74..6e319ff8be8 100644
--- a/libgo/go/mime/grammar.go
+++ b/libgo/go/mime/grammar.go
@@ -9,13 +9,13 @@ import (
)
// isTSpecial returns true if rune is in 'tspecials' as defined by RFC
-// 1531 and RFC 2045.
+// 1521 and RFC 2045.
func isTSpecial(rune int) bool {
return strings.IndexRune(`()<>@,;:\"/[]?=`, rune) != -1
}
// IsTokenChar returns true if rune is in 'token' as defined by RFC
-// 1531 and RFC 2045.
+// 1521 and RFC 2045.
func IsTokenChar(rune int) bool {
// token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
// or tspecials>
diff --git a/libgo/go/mime/mediatype.go b/libgo/go/mime/mediatype.go
index f28ff3e9681..40c735c5baa 100644
--- a/libgo/go/mime/mediatype.go
+++ b/libgo/go/mime/mediatype.go
@@ -31,11 +31,13 @@ func validMediaTypeOrDisposition(s string) bool {
}
// 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.
+// parameters, per RFC 1521. Media types are the values in
+// Content-Type and Content-Disposition headers (RFC 2183).
+// On success, ParseMediaType returns the media type converted
+// to lowercase and trimmed of white space. The returned params
+// is always a non-nil map. Params maps from the lowercase
+// attribute to the attribute value with its case preserved.
+// 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 {
@@ -132,7 +134,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string) {
}
func decode2231Enc(v string) string {
- sv := strings.Split(v, "'", 3)
+ sv := strings.SplitN(v, "'", 3)
if len(sv) != 3 {
return ""
}
@@ -211,6 +213,7 @@ func consumeMediaParam(v string) (param, value, rest string) {
rest = rest[1:] // consume semicolon
rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
param, rest = consumeToken(rest)
+ param = strings.ToLower(param)
if param == "" {
return "", "", v
}
diff --git a/libgo/go/mime/mediatype_test.go b/libgo/go/mime/mediatype_test.go
index 454ddd03778..93264bd09a1 100644
--- a/libgo/go/mime/mediatype_test.go
+++ b/libgo/go/mime/mediatype_test.go
@@ -60,6 +60,7 @@ func TestConsumeMediaParam(t *testing.T) {
{" ; foo=bar", "foo", "bar", ""},
{"; 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"},
@@ -127,7 +128,7 @@ func TestParseMediaType(t *testing.T) {
`URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"`,
"message/external-body",
m("access-type", "URL",
- "URL", "ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar")},
+ "url", "ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar")},
{`application/x-stuff; ` +
`title*0*=us-ascii'en'This%20is%20even%20more%20; ` +
diff --git a/libgo/go/mime/multipart/formdata.go b/libgo/go/mime/multipart/formdata.go
index 5f328656590..91404d6f41c 100644
--- a/libgo/go/mime/multipart/formdata.go
+++ b/libgo/go/mime/multipart/formdata.go
@@ -19,7 +19,7 @@ import (
// a Content-Disposition of "form-data".
// It stores up to maxMemory bytes of the file parts in memory
// and the remainder on disk in temporary files.
-func (r *multiReader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
+func (r *Reader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
defer func() {
if err != nil {
diff --git a/libgo/go/mime/multipart/formdata_test.go b/libgo/go/mime/multipart/formdata_test.go
index b56e2a430e0..4bc4649317a 100644
--- a/libgo/go/mime/multipart/formdata_test.go
+++ b/libgo/go/mime/multipart/formdata_test.go
@@ -31,10 +31,12 @@ func TestReadForm(t *testing.T) {
if _, ok := fd.(*os.File); ok {
t.Error("file is *os.File, should not be")
}
+ fd.Close()
fd = testFile(t, f.File["fileb"][0], "fileb.txt", filebContents)
if _, ok := fd.(*os.File); !ok {
- t.Error("file has unexpected underlying type %T", fd)
+ t.Errorf("file has unexpected underlying type %T", fd)
}
+ fd.Close()
}
func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File {
diff --git a/libgo/go/mime/multipart/multipart.go b/libgo/go/mime/multipart/multipart.go
index 9affa112611..2533bd337dc 100644
--- a/libgo/go/mime/multipart/multipart.go
+++ b/libgo/go/mime/multipart/multipart.go
@@ -21,28 +21,15 @@ import (
"mime"
"net/textproto"
"os"
- "regexp"
)
-var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)")
+// TODO(bradfitz): inline these once the compiler can inline them in
+// read-only situation (such as bytes.HasSuffix)
+var lf = []byte("\n")
+var crlf = []byte("\r\n")
var emptyParams = make(map[string]string)
-// Reader is an iterator over parts in a MIME multipart body.
-// Reader's underlying parser consumes its input as needed. Seeking
-// isn't supported.
-type Reader interface {
- // NextPart returns the next part in the multipart or an error.
- // When there are no more parts, the error os.EOF is returned.
- NextPart() (*Part, os.Error)
-
- // ReadForm parses an entire multipart message whose parts have
- // a Content-Disposition of "form-data".
- // It stores up to maxMemory bytes of the file parts in memory
- // and the remainder on disk in temporary files.
- ReadForm(maxMemory int64) (*Form, os.Error)
-}
-
// A Part represents a single part in a multipart body.
type Part struct {
// The headers of the body, if any, with the keys canonicalized
@@ -51,7 +38,7 @@ type Part struct {
Header textproto.MIMEHeader
buffer *bytes.Buffer
- mr *multiReader
+ mr *Reader
disposition string
dispositionParams map[string]string
@@ -71,7 +58,6 @@ func (p *Part) FormName() string {
return p.dispositionParams["name"]
}
-
// FileName returns the filename parameter of the Part's
// Content-Disposition header.
func (p *Part) FileName() string {
@@ -91,20 +77,19 @@ func (p *Part) parseContentDisposition() {
// NewReader creates a new multipart Reader reading from r using the
// given MIME boundary.
-func NewReader(reader io.Reader, boundary string) Reader {
+func NewReader(reader io.Reader, boundary string) *Reader {
b := []byte("\r\n--" + boundary + "--")
- return &multiReader{
+ return &Reader{
bufReader: bufio.NewReader(reader),
+ nl: b[:2],
nlDashBoundary: b[:len(b)-2],
dashBoundaryDash: b[2:],
dashBoundary: b[2 : len(b)-2],
}
}
-// Implementation ....
-
-func newPart(mr *multiReader) (*Part, os.Error) {
+func newPart(mr *Reader) (*Part, os.Error) {
bp := &Part{
Header: make(map[string][]string),
mr: mr,
@@ -117,22 +102,12 @@ func newPart(mr *multiReader) (*Part, os.Error) {
}
func (bp *Part) populateHeaders() os.Error {
- for {
- lineBytes, err := bp.mr.bufReader.ReadSlice('\n')
- if err != nil {
- return err
- }
- line := string(lineBytes)
- if line == "\n" || line == "\r\n" {
- return nil
- }
- if matches := headerRegexp.FindStringSubmatch(line); len(matches) == 3 {
- bp.Header.Add(matches[1], matches[2])
- continue
- }
- return os.NewError("Unexpected header line found parsing multipart body")
+ r := textproto.NewReader(bp.mr.bufReader)
+ header, err := r.ReadMIMEHeader()
+ if err == nil {
+ bp.Header = header
}
- panic("unreachable")
+ return err
}
// Read reads the body of a part, after its headers and before the
@@ -188,16 +163,21 @@ func (bp *Part) Close() os.Error {
return nil
}
-type multiReader struct {
+// Reader is an iterator over parts in a MIME multipart body.
+// Reader's underlying parser consumes its input as needed. Seeking
+// isn't supported.
+type Reader struct {
bufReader *bufio.Reader
currentPart *Part
partsRead int
- nlDashBoundary, dashBoundaryDash, dashBoundary []byte
+ nl, nlDashBoundary, dashBoundaryDash, dashBoundary []byte
}
-func (mr *multiReader) NextPart() (*Part, os.Error) {
+// NextPart returns the next part in the multipart or an error.
+// When there are no more parts, the error os.EOF is returned.
+func (mr *Reader) NextPart() (*Part, os.Error) {
if mr.currentPart != nil {
mr.currentPart.Close()
}
@@ -233,11 +213,11 @@ func (mr *multiReader) NextPart() (*Part, os.Error) {
continue
}
- if bytes.Equal(line, []byte("\r\n")) {
- // Consume the "\r\n" separator between the
- // body of the previous part and the boundary
- // line we now expect will follow. (either a
- // new part or the end boundary)
+ // Consume the "\n" or "\r\n" separator between the
+ // body of the previous part and the boundary line we
+ // now expect will follow. (either a new part or the
+ // end boundary)
+ if bytes.Equal(line, mr.nl) {
expectNewPart = true
continue
}
@@ -247,7 +227,7 @@ func (mr *multiReader) NextPart() (*Part, os.Error) {
panic("unreachable")
}
-func (mr *multiReader) isBoundaryDelimiterLine(line []byte) bool {
+func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
// http://tools.ietf.org/html/rfc2046#section-5.1
// The boundary delimiter line is then defined as a line
// consisting entirely of two hyphen characters ("-",
@@ -257,13 +237,17 @@ func (mr *multiReader) isBoundaryDelimiterLine(line []byte) bool {
if !bytes.HasPrefix(line, mr.dashBoundary) {
return false
}
- if bytes.HasSuffix(line, []byte("\r\n")) {
- return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-2])
+ if bytes.HasSuffix(line, mr.nl) {
+ return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-len(mr.nl)])
}
// Violate the spec and also support newlines without the
// carriage return...
- if bytes.HasSuffix(line, []byte("\n")) {
- return onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1])
+ if mr.partsRead == 0 && bytes.HasSuffix(line, lf) {
+ if onlyHorizontalWhitespace(line[len(mr.dashBoundary) : len(line)-1]) {
+ mr.nl = mr.nl[1:]
+ mr.nlDashBoundary = mr.nlDashBoundary[1:]
+ return true
+ }
}
return false
}
@@ -280,5 +264,5 @@ func onlyHorizontalWhitespace(s []byte) bool {
func hasPrefixThenNewline(s, prefix []byte) bool {
return bytes.HasPrefix(s, prefix) &&
(len(s) == len(prefix)+1 && s[len(s)-1] == '\n' ||
- len(s) == len(prefix)+2 && bytes.HasSuffix(s, []byte("\r\n")))
+ len(s) == len(prefix)+2 && bytes.HasSuffix(s, crlf))
}
diff --git a/libgo/go/mime/multipart/multipart_test.go b/libgo/go/mime/multipart/multipart_test.go
index 8222fbd8a4d..38079e53a19 100644
--- a/libgo/go/mime/multipart/multipart_test.go
+++ b/libgo/go/mime/multipart/multipart_test.go
@@ -25,7 +25,7 @@ func TestHorizontalWhitespace(t *testing.T) {
}
func TestBoundaryLine(t *testing.T) {
- mr := NewReader(strings.NewReader(""), "myBoundary").(*multiReader)
+ mr := NewReader(strings.NewReader(""), "myBoundary")
if !mr.isBoundaryDelimiterLine([]byte("--myBoundary\r\n")) {
t.Error("expected")
}
@@ -81,7 +81,7 @@ func TestNameAccessors(t *testing.T) {
var longLine = strings.Repeat("\n\n\r\r\r\n\r\000", (1<<20)/8)
-func testMultipartBody() string {
+func testMultipartBody(sep string) string {
testBody := `
This is a multi-part message. This line is ignored.
--MyBoundary
@@ -112,21 +112,26 @@ never read data
useless trailer
`
- testBody = strings.Replace(testBody, "\n", "\r\n", -1)
+ testBody = strings.Replace(testBody, "\n", sep, -1)
return strings.Replace(testBody, "[longline]", longLine, 1)
}
func TestMultipart(t *testing.T) {
- bodyReader := strings.NewReader(testMultipartBody())
- testMultipart(t, bodyReader)
+ bodyReader := strings.NewReader(testMultipartBody("\r\n"))
+ testMultipart(t, bodyReader, false)
+}
+
+func TestMultipartOnlyNewlines(t *testing.T) {
+ bodyReader := strings.NewReader(testMultipartBody("\n"))
+ testMultipart(t, bodyReader, true)
}
func TestMultipartSlowInput(t *testing.T) {
- bodyReader := strings.NewReader(testMultipartBody())
- testMultipart(t, &slowReader{bodyReader})
+ bodyReader := strings.NewReader(testMultipartBody("\r\n"))
+ testMultipart(t, &slowReader{bodyReader}, false)
}
-func testMultipart(t *testing.T, r io.Reader) {
+func testMultipart(t *testing.T, r io.Reader, onlyNewlines bool) {
reader := NewReader(r, "MyBoundary")
buf := new(bytes.Buffer)
@@ -136,21 +141,28 @@ func testMultipart(t *testing.T, r io.Reader) {
t.Error("Expected part1")
return
}
- if part.Header.Get("Header1") != "value1" {
- t.Error("Expected Header1: value")
+ if x := part.Header.Get("Header1"); x != "value1" {
+ t.Errorf("part.Header.Get(%q) = %q, want %q", "Header1", x, "value1")
}
- if part.Header.Get("foo-bar") != "baz" {
- t.Error("Expected foo-bar: baz")
+ if x := part.Header.Get("foo-bar"); x != "baz" {
+ t.Errorf("part.Header.Get(%q) = %q, want %q", "foo-bar", x, "baz")
}
- if part.Header.Get("Foo-Bar") != "baz" {
- t.Error("Expected Foo-Bar: baz")
+ if x := part.Header.Get("Foo-Bar"); x != "baz" {
+ t.Errorf("part.Header.Get(%q) = %q, want %q", "Foo-Bar", x, "baz")
}
buf.Reset()
if _, err := io.Copy(buf, part); err != nil {
t.Errorf("part 1 copy: %v", err)
}
- expectEq(t, "My value\r\nThe end.",
- buf.String(), "Value of first part")
+
+ adjustNewlines := func(s string) string {
+ if onlyNewlines {
+ return strings.Replace(s, "\r\n", "\n", -1)
+ }
+ return s
+ }
+
+ expectEq(t, adjustNewlines("My value\r\nThe end."), buf.String(), "Value of first part")
// Part2
part, err = reader.NextPart()
@@ -187,7 +199,7 @@ func testMultipart(t *testing.T, r io.Reader) {
if _, err := io.Copy(buf, part); err != nil {
t.Errorf("part 3 copy: %v", err)
}
- expectEq(t, "Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n",
+ expectEq(t, adjustNewlines("Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n"),
buf.String(), "body of part 3")
// Part4
@@ -203,7 +215,7 @@ func testMultipart(t *testing.T, r io.Reader) {
t.Error("Didn't expect a fifth part.")
}
if err != os.EOF {
- t.Errorf("On fifth part expected os.EOF; got %v", err)
+ t.Errorf("On fifth part expected os.EOF; got %v", err)
}
}
@@ -307,6 +319,29 @@ Oh no, premature EOF!
}
}
+func TestZeroLengthBody(t *testing.T) {
+ testBody := strings.Replace(`
+This is a multi-part message. This line is ignored.
+--MyBoundary
+foo: bar
+
+
+--MyBoundary--
+`, "\n", "\r\n", -1)
+ r := NewReader(strings.NewReader(testBody), "MyBoundary")
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("didn't get a part")
+ }
+ n, err := io.Copy(ioutil.Discard, part)
+ if err != nil {
+ t.Errorf("error reading part: %v", err)
+ }
+ if n != 0 {
+ t.Errorf("read %d bytes; expected 0", n)
+ }
+}
+
type slowReader struct {
r io.Reader
}
@@ -317,3 +352,29 @@ func (s *slowReader) Read(p []byte) (int, os.Error) {
}
return s.r.Read(p[:1])
}
+
+func TestLineContinuation(t *testing.T) {
+ // This body, extracted from an email, contains headers that span multiple
+ // lines.
+
+ // TODO: The original mail ended with a double-newline before the
+ // final delimiter; this was manually edited to use a CRLF.
+ testBody :=
+ "\n--Apple-Mail-2-292336769\nContent-Transfer-Encoding: 7bit\nContent-Type: text/plain;\n\tcharset=US-ASCII;\n\tdelsp=yes;\n\tformat=flowed\n\nI'm finding the same thing happening on my system (10.4.1).\n\n\n--Apple-Mail-2-292336769\nContent-Transfer-Encoding: quoted-printable\nContent-Type: text/html;\n\tcharset=ISO-8859-1\n\n<HTML><BODY>I'm finding the same thing =\nhappening on my system (10.4.1).=A0 But I built it with XCode =\n2.0.</BODY></=\nHTML>=\n\r\n--Apple-Mail-2-292336769--\n"
+
+ r := NewReader(strings.NewReader(testBody), "Apple-Mail-2-292336769")
+
+ for i := 0; i < 2; i++ {
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("didn't get a part")
+ }
+ n, err := io.Copy(ioutil.Discard, part)
+ if err != nil {
+ t.Errorf("error reading part: %v", err)
+ }
+ if n <= 0 {
+ t.Errorf("read %d bytes; expected >0", n)
+ }
+ }
+}
diff --git a/libgo/go/mime/multipart/writer.go b/libgo/go/mime/multipart/writer.go
new file mode 100644
index 00000000000..97a8897b299
--- /dev/null
+++ b/libgo/go/mime/multipart/writer.go
@@ -0,0 +1,157 @@
+// 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 multipart
+
+import (
+ "bytes"
+ "crypto/rand"
+ "fmt"
+ "io"
+ "net/textproto"
+ "os"
+ "strings"
+)
+
+// A Writer generates multipart messages.
+type Writer struct {
+ w io.Writer
+ boundary string
+ lastpart *part
+}
+
+// NewWriter returns a new multipart Writer with a random boundary,
+// writing to w.
+func NewWriter(w io.Writer) *Writer {
+ return &Writer{
+ w: w,
+ boundary: randomBoundary(),
+ }
+}
+
+// Boundary returns the Writer's randomly selected boundary string.
+func (w *Writer) Boundary() string {
+ return w.boundary
+}
+
+// FormDataContentType returns the Content-Type for an HTTP
+// multipart/form-data with this Writer's Boundary.
+func (w *Writer) FormDataContentType() string {
+ return "multipart/form-data; boundary=" + w.boundary
+}
+
+func randomBoundary() string {
+ var buf [30]byte
+ _, err := io.ReadFull(rand.Reader, buf[:])
+ if err != nil {
+ panic(err)
+ }
+ return fmt.Sprintf("%x", buf[:])
+}
+
+// CreatePart creates a new multipart section with the provided
+// header. The body of the part should be written to the returned
+// Writer. After calling CreatePart, any previous part may no longer
+// be written to.
+func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, os.Error) {
+ if w.lastpart != nil {
+ if err := w.lastpart.close(); err != nil {
+ return nil, err
+ }
+ }
+ var b bytes.Buffer
+ if w.lastpart != nil {
+ fmt.Fprintf(&b, "\r\n--%s\r\n", w.boundary)
+ } else {
+ fmt.Fprintf(&b, "--%s\r\n", w.boundary)
+ }
+ // TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort
+ // and clean, like http.Header.Write(w) does.
+ for k, vv := range header {
+ for _, v := range vv {
+ fmt.Fprintf(&b, "%s: %s\r\n", k, v)
+ }
+ }
+ fmt.Fprintf(&b, "\r\n")
+ _, err := io.Copy(w.w, &b)
+ if err != nil {
+ return nil, err
+ }
+ p := &part{
+ mw: w,
+ }
+ w.lastpart = p
+ return p, nil
+}
+
+func escapeQuotes(s string) string {
+ s = strings.Replace(s, "\\", "\\\\", -1)
+ s = strings.Replace(s, "\"", "\\\"", -1)
+ return s
+}
+
+// CreateFormFile is a convenience wrapper around CreatePart. It creates
+// a new form-data header with the provided field name and file name.
+func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, os.Error) {
+ h := make(textproto.MIMEHeader)
+ h.Set("Content-Disposition",
+ fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
+ escapeQuotes(fieldname), escapeQuotes(filename)))
+ h.Set("Content-Type", "application/octet-stream")
+ return w.CreatePart(h)
+}
+
+// CreateFormField calls CreatePart with a header using the
+// given field name.
+func (w *Writer) CreateFormField(fieldname string) (io.Writer, os.Error) {
+ h := make(textproto.MIMEHeader)
+ h.Set("Content-Disposition",
+ fmt.Sprintf(`form-data; name="%s"`, escapeQuotes(fieldname)))
+ return w.CreatePart(h)
+}
+
+// WriteField calls CreateFormField and then writes the given value.
+func (w *Writer) WriteField(fieldname, value string) os.Error {
+ p, err := w.CreateFormField(fieldname)
+ if err != nil {
+ return err
+ }
+ _, err = p.Write([]byte(value))
+ return err
+}
+
+// Close finishes the multipart message and writes the trailing
+// boundary end line to the output.
+func (w *Writer) Close() os.Error {
+ if w.lastpart != nil {
+ if err := w.lastpart.close(); err != nil {
+ return err
+ }
+ w.lastpart = nil
+ }
+ _, err := fmt.Fprintf(w.w, "\r\n--%s--\r\n", w.boundary)
+ return err
+}
+
+type part struct {
+ mw *Writer
+ closed bool
+ we os.Error // last error that occurred writing
+}
+
+func (p *part) close() os.Error {
+ p.closed = true
+ return p.we
+}
+
+func (p *part) Write(d []byte) (n int, err os.Error) {
+ if p.closed {
+ return 0, os.NewError("multipart: can't write to finished part")
+ }
+ n, err = p.mw.w.Write(d)
+ if err != nil {
+ p.we = err
+ }
+ return
+}
diff --git a/libgo/go/mime/multipart/writer_test.go b/libgo/go/mime/multipart/writer_test.go
new file mode 100644
index 00000000000..494e936c4c6
--- /dev/null
+++ b/libgo/go/mime/multipart/writer_test.go
@@ -0,0 +1,78 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+)
+
+func TestWriter(t *testing.T) {
+ fileContents := []byte("my file contents")
+
+ var b bytes.Buffer
+ w := NewWriter(&b)
+ {
+ part, err := w.CreateFormFile("myfile", "my-file.txt")
+ if err != nil {
+ t.Fatalf("CreateFormFile: %v", err)
+ }
+ part.Write(fileContents)
+ err = w.WriteField("key", "val")
+ if err != nil {
+ t.Fatalf("WriteField: %v", err)
+ }
+ part.Write([]byte("val"))
+ err = w.Close()
+ if err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+ s := b.String()
+ if len(s) == 0 {
+ t.Fatal("String: unexpected empty result")
+ }
+ if s[0] == '\r' || s[0] == '\n' {
+ t.Fatal("String: unexpected newline")
+ }
+ }
+
+ r := NewReader(&b, w.Boundary())
+
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("part 1: %v", err)
+ }
+ if g, e := part.FormName(), "myfile"; g != e {
+ t.Errorf("part 1: want form name %q, got %q", e, g)
+ }
+ slurp, err := ioutil.ReadAll(part)
+ if err != nil {
+ t.Fatalf("part 1: ReadAll: %v", err)
+ }
+ if e, g := string(fileContents), string(slurp); e != g {
+ t.Errorf("part 1: want contents %q, got %q", e, g)
+ }
+
+ part, err = r.NextPart()
+ if err != nil {
+ t.Fatalf("part 2: %v", err)
+ }
+ if g, e := part.FormName(), "key"; g != e {
+ t.Errorf("part 2: want form name %q, got %q", e, g)
+ }
+ slurp, err = ioutil.ReadAll(part)
+ if err != nil {
+ t.Fatalf("part 2: ReadAll: %v", err)
+ }
+ if e, g := "val", string(slurp); e != g {
+ t.Errorf("part 2: want contents %q, got %q", e, g)
+ }
+
+ part, err = r.NextPart()
+ if part != nil || err == nil {
+ t.Fatalf("expected end of parts; got %v, %v", part, err)
+ }
+}
diff --git a/libgo/go/mime/type.go b/libgo/go/mime/type.go
index 8c43b81b0c5..8ecfe9a37b1 100644
--- a/libgo/go/mime/type.go
+++ b/libgo/go/mime/type.go
@@ -19,7 +19,7 @@ var typeFiles = []string{
}
var mimeTypes = map[string]string{
- ".css": "text/css",
+ ".css": "text/css; charset=utf-8",
".gif": "image/gif",
".htm": "text/html; charset=utf-8",
".html": "text/html; charset=utf-8",
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
index 16896b4269b..10c67dcc40a 100644
--- a/libgo/go/net/dial.go
+++ b/libgo/go/net/dial.go
@@ -6,6 +6,28 @@ package net
import "os"
+func resolveNetAddr(op, net, addr string) (a Addr, err os.Error) {
+ if addr == "" {
+ return nil, &OpError{op, net, nil, errMissingAddress}
+ }
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ a, err = ResolveTCPAddr(net, addr)
+ case "udp", "udp4", "udp6":
+ a, err = ResolveUDPAddr(net, addr)
+ case "unix", "unixgram", "unixpacket":
+ a, err = ResolveUnixAddr(net, addr)
+ case "ip", "ip4", "ip6":
+ a, err = ResolveIPAddr(net, addr)
+ default:
+ err = UnknownNetworkError(net)
+ }
+ if err != nil {
+ return nil, &OpError{op, net + " " + addr, nil, err}
+ }
+ return
+}
+
// Dial connects to the address addr on the network net.
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
@@ -23,56 +45,26 @@ import "os"
// Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
//
func Dial(net, addr string) (c Conn, err os.Error) {
- raddr := addr
- if raddr == "" {
- return nil, &OpError{"dial", net, nil, errMissingAddress}
+ addri, err := resolveNetAddr("dial", net, addr)
+ if err != nil {
+ return nil, err
}
- switch net {
- case "tcp", "tcp4", "tcp6":
- var ra *TCPAddr
- if ra, err = ResolveTCPAddr(net, raddr); err != nil {
- goto Error
- }
- c, err := DialTCP(net, nil, ra)
- if err != nil {
- return nil, err
- }
- return c, nil
- case "udp", "udp4", "udp6":
- var ra *UDPAddr
- if ra, err = ResolveUDPAddr(net, raddr); err != nil {
- goto Error
- }
- c, err := DialUDP(net, nil, ra)
- if err != nil {
- return nil, err
- }
- return c, nil
- case "unix", "unixgram", "unixpacket":
- var ra *UnixAddr
- if ra, err = ResolveUnixAddr(net, raddr); err != nil {
- goto Error
- }
+ switch ra := addri.(type) {
+ case *TCPAddr:
+ c, err = DialTCP(net, nil, ra)
+ case *UDPAddr:
+ c, err = DialUDP(net, nil, ra)
+ case *UnixAddr:
c, err = DialUnix(net, nil, ra)
- if err != nil {
- return nil, err
- }
- return c, nil
- case "ip", "ip4", "ip6":
- var ra *IPAddr
- if ra, err = ResolveIPAddr(raddr); err != nil {
- goto Error
- }
- c, err := DialIP(net, nil, ra)
- if err != nil {
- return nil, err
- }
- return c, nil
-
+ case *IPAddr:
+ c, err = DialIP(net, nil, ra)
+ default:
+ err = UnknownNetworkError(net)
+ }
+ if err != nil {
+ return nil, &OpError{"dial", net + " " + addr, nil, err}
}
- err = UnknownNetworkError(net)
-Error:
- return nil, &OpError{"dial", net + " " + raddr, nil, err}
+ return
}
// Listen announces on the local network address laddr.
@@ -139,12 +131,13 @@ func ListenPacket(net, laddr string) (c PacketConn, err os.Error) {
return c, nil
}
- if i := last(net, ':'); i > 0 {
- switch net[0:i] {
+ var rawnet string
+ if rawnet, _, err = splitNetProto(net); err != nil {
+ switch rawnet {
case "ip", "ip4", "ip6":
var la *IPAddr
if laddr != "" {
- if la, err = ResolveIPAddr(laddr); err != nil {
+ if la, err = ResolveIPAddr(rawnet, laddr); err != nil {
return nil, err
}
}
diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go
index e90c4f3f894..9ad1770dab7 100644
--- a/libgo/go/net/dialgoogle_test.go
+++ b/libgo/go/net/dialgoogle_test.go
@@ -105,14 +105,12 @@ func TestDialGoogleIPv4(t *testing.T) {
doDial(t, "tcp", addr)
if addr[0] != '[' {
doDial(t, "tcp4", addr)
- if !preferIPv4 {
- // make sure preferIPv4 flag works.
- preferIPv4 = true
+ if supportsIPv6 {
+ // make sure syscall.SocketDisableIPv6 flag works.
syscall.SocketDisableIPv6 = true
doDial(t, "tcp", addr)
doDial(t, "tcp4", addr)
syscall.SocketDisableIPv6 = false
- preferIPv4 = false
}
}
}
@@ -132,7 +130,7 @@ func TestDialGoogleIPv6(t *testing.T) {
return
}
// Only run tcp6 if the kernel will take it.
- if !*ipv6 || !kernelSupportsIPv6() {
+ if !*ipv6 || !supportsIPv6 {
return
}
diff --git a/libgo/go/net/dict/dict.go b/libgo/go/net/dict/dict.go
index 42f6553ad33..b146ea2123c 100644
--- a/libgo/go/net/dict/dict.go
+++ b/libgo/go/net/dict/dict.go
@@ -7,7 +7,6 @@
package dict
import (
- "container/vector"
"net/textproto"
"os"
"strconv"
@@ -144,7 +143,7 @@ func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
// Fields are space separated unquoted words
// or quoted with single or double quote.
func fields(s string) ([]string, os.Error) {
- var v vector.StringVector
+ var v []string
i := 0
for {
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
@@ -170,7 +169,7 @@ func fields(s string) ([]string, os.Error) {
break
}
}
- v.Push(unquote(s[i+1 : j-1]))
+ v = append(v, unquote(s[i+1:j-1]))
i = j
} else {
// atom
@@ -180,7 +179,7 @@ func fields(s string) ([]string, os.Error) {
break
}
}
- v.Push(s[i:j])
+ v = append(v, s[i:j])
i = j
}
if i < len(s) {
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
index 3466003fab8..93c04f6b590 100644
--- a/libgo/go/net/dnsclient.go
+++ b/libgo/go/net/dnsclient.go
@@ -2,16 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// DNS client: see RFC 1035.
-// Has to be linked into package net for Dial.
-
-// TODO(rsc):
-// Check periodically whether /etc/resolv.conf has changed.
-// Could potentially handle many outstanding lookups faster.
-// Could have a small cache.
-// Random UDP source port (net.Dial should do that for us).
-// Random request IDs.
-
package net
import (
@@ -19,8 +9,6 @@ import (
"fmt"
"os"
"rand"
- "sync"
- "time"
"sort"
)
@@ -49,54 +37,31 @@ func (e *DNSError) Temporary() bool { return e.IsTimeout }
const noSuchHost = "no such host"
-// Send a request on the connection and hope for a reply.
-// Up to cfg.attempts attempts.
-func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Error) {
- if len(name) >= 256 {
- return nil, &DNSError{Error: "name too long", Name: name}
- }
- out := new(dnsMsg)
- out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
- out.question = []dnsQuestion{
- {name, qtype, dnsClassINET},
- }
- out.recursion_desired = true
- msg, ok := out.Pack()
- if !ok {
- return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
+// address addr suitable for rDNS (PTR) record lookup or an error if it fails
+// to parse the IP address.
+func reverseaddr(addr string) (arpa string, err os.Error) {
+ ip := ParseIP(addr)
+ if ip == nil {
+ return "", &DNSError{Error: "unrecognized address", Name: addr}
}
-
- for attempt := 0; attempt < cfg.attempts; attempt++ {
- n, err := c.Write(msg)
- if err != nil {
- return nil, err
- }
-
- c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
-
- buf := make([]byte, 2000) // More than enough.
- n, err = c.Read(buf)
- if err != nil {
- if e, ok := err.(Error); ok && e.Timeout() {
- continue
- }
- return nil, err
- }
- buf = buf[0:n]
- in := new(dnsMsg)
- if !in.Unpack(buf) || in.id != out.id {
- continue
- }
- return in, nil
+ if ip.To4() != nil {
+ return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
}
- var server string
- if a := c.RemoteAddr(); a != nil {
- server = a.String()
+ // Must be IPv6
+ var buf bytes.Buffer
+ // Add it, in reverse, to the buffer
+ for i := len(ip) - 1; i >= 0; i-- {
+ s := fmt.Sprintf("%02x", ip[i])
+ buf.WriteByte(s[1])
+ buf.WriteByte('.')
+ buf.WriteByte(s[0])
+ buf.WriteByte('.')
}
- return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+ // Append "ip6.arpa." and return (buf already has the final .)
+ return buf.String() + "ip6.arpa.", nil
}
-
// Find answer for name in dns message.
// On return, if err == nil, addrs != nil.
func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
@@ -150,63 +115,6 @@ Cname:
return "", nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
}
-// Do a lookup for a single name, which must be rooted
-// (otherwise answer will not find the answers).
-func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- if len(cfg.servers) == 0 {
- return "", nil, &DNSError{Error: "no DNS servers", Name: name}
- }
- for i := 0; i < len(cfg.servers); i++ {
- // Calling Dial here is scary -- we have to be sure
- // not to dial a name that will require a DNS lookup,
- // or Dial will call back here to translate it.
- // The DNS config parser has already checked that
- // all the cfg.servers[i] are IP addresses, which
- // Dial will use without a DNS lookup.
- server := cfg.servers[i] + ":53"
- c, cerr := Dial("udp", server)
- if cerr != nil {
- err = cerr
- continue
- }
- msg, merr := exchange(cfg, c, name, qtype)
- c.Close()
- if merr != nil {
- err = merr
- continue
- }
- cname, addrs, err = answer(name, server, msg, qtype)
- if err == nil || err.(*DNSError).Error == noSuchHost {
- break
- }
- }
- return
-}
-
-func convertRR_A(records []dnsRR) []IP {
- addrs := make([]IP, len(records))
- for i, rr := range records {
- a := rr.(*dnsRR_A).A
- addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
- }
- return addrs
-}
-
-func convertRR_AAAA(records []dnsRR) []IP {
- addrs := make([]IP, len(records))
- for i, rr := range records {
- a := make(IP, 16)
- copy(a, rr.(*dnsRR_AAAA).AAAA[:])
- addrs[i] = a
- }
- return addrs
-}
-
-var cfg *dnsConfig
-var dnserr os.Error
-
-func loadConfig() { cfg, dnserr = dnsReadConfig() }
-
func isDomainName(s string) bool {
// See RFC 1035, RFC 3696.
if len(s) == 0 {
@@ -255,166 +163,63 @@ func isDomainName(s string) bool {
return ok
}
-var onceLoadConfig sync.Once
-
-func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- if !isDomainName(name) {
- return name, nil, &DNSError{Error: "invalid domain name", Name: name}
- }
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- // If name is rooted (trailing dot) or has enough dots,
- // try it by itself first.
- rooted := len(name) > 0 && name[len(name)-1] == '.'
- if rooted || count(name, '.') >= cfg.ndots {
- rname := name
- if !rooted {
- rname += "."
- }
- // Can try as ordinary name.
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- }
- if rooted {
- return
- }
+// An SRV represents a single DNS SRV record.
+type SRV struct {
+ Target string
+ Port uint16
+ Priority uint16
+ Weight uint16
+}
- // Otherwise, try suffixes.
- for i := 0; i < len(cfg.search); i++ {
- rname := name + "." + cfg.search[i]
- if rname[len(rname)-1] != '.' {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- }
+// byPriorityWeight sorts SRV records by ascending priority and weight.
+type byPriorityWeight []*SRV
- // Last ditch effort: try unsuffixed.
- rname := name
- if !rooted {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- return
-}
+func (s byPriorityWeight) Len() int { return len(s) }
-// goLookupHost is the native Go implementation of LookupHost.
-// Used only if cgoLookupHost refuses to handle the request
-// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupHost(name string) (addrs []string, err os.Error) {
- // Use entries from /etc/hosts if they match.
- addrs = lookupStaticHost(name)
- if len(addrs) > 0 {
- return
- }
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- ips, err := goLookupIP(name)
- if err != nil {
- return
- }
- addrs = make([]string, 0, len(ips))
- for _, ip := range ips {
- addrs = append(addrs, ip.String())
- }
- return
-}
+func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-// goLookupIP is the native Go implementation of LookupIP.
-// Used only if cgoLookupIP refuses to handle the request
-// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupIP(name string) (addrs []IP, err os.Error) {
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- var records []dnsRR
- var cname string
- cname, records, err = lookup(name, dnsTypeA)
- if err != nil {
- return
- }
- addrs = convertRR_A(records)
- if cname != "" {
- name = cname
- }
- _, records, err = lookup(name, dnsTypeAAAA)
- if err != nil && len(addrs) > 0 {
- // Ignore error because A lookup succeeded.
- err = nil
- }
- if err != nil {
- return
- }
- addrs = append(addrs, convertRR_AAAA(records)...)
- return
+func (s byPriorityWeight) Less(i, j int) bool {
+ return s[i].Priority < s[j].Priority ||
+ (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
}
-// goLookupCNAME is the native Go implementation of LookupCNAME.
-// Used only if cgoLookupCNAME refuses to handle the request
-// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupCNAME(name string) (cname string, err os.Error) {
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
+// shuffleByWeight shuffles SRV records by weight using the algorithm
+// described in RFC 2782.
+func (addrs byPriorityWeight) shuffleByWeight() {
+ sum := 0
+ for _, addr := range addrs {
+ sum += int(addr.Weight)
}
- _, rr, err := lookup(name, dnsTypeCNAME)
- if err != nil {
- return
+ for sum > 0 && len(addrs) > 1 {
+ s := 0
+ n := rand.Intn(sum + 1)
+ for i := range addrs {
+ s += int(addrs[i].Weight)
+ if s >= n {
+ if i > 0 {
+ t := addrs[i]
+ copy(addrs[1:i+1], addrs[0:i])
+ addrs[0] = t
+ }
+ break
+ }
+ }
+ sum -= int(addrs[0].Weight)
+ addrs = addrs[1:]
}
- cname = rr[0].(*dnsRR_CNAME).Cname
- return
}
-// An SRV represents a single DNS SRV record.
-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, rr := range records {
- r := rr.(*dnsRR_SRV)
- addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+// sort reorders SRV records as specified in RFC 2782.
+func (addrs byPriorityWeight) sort() {
+ sort.Sort(addrs)
+ i := 0
+ for j := 1; j < len(addrs); j++ {
+ if addrs[i].Priority != addrs[j].Priority {
+ addrs[i:j].shuffleByWeight()
+ i = j
+ }
}
- return
+ addrs[i:].shuffleByWeight()
}
// An MX represents a single DNS MX record.
@@ -432,72 +237,11 @@ func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-// LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mx []*MX, err os.Error) {
- _, rr, err := lookup(name, dnsTypeMX)
- if err != nil {
- return
- }
- mx = make([]*MX, len(rr))
- for i := range rr {
- r := rr[i].(*dnsRR_MX)
- mx[i] = &MX{r.Mx, r.Pref}
- }
- // Shuffle the records to match RFC 5321 when sorted
- for i := range mx {
+// sort reorders MX records as specified in RFC 5321.
+func (s byPref) sort() {
+ for i := range s {
j := rand.Intn(i + 1)
- mx[i], mx[j] = mx[j], mx[i]
- }
- sort.Sort(byPref(mx))
- return
-}
-
-// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
-// address addr suitable for rDNS (PTR) record lookup or an error if it fails
-// to parse the IP address.
-func reverseaddr(addr string) (arpa string, err os.Error) {
- ip := ParseIP(addr)
- if ip == nil {
- return "", &DNSError{Error: "unrecognized address", Name: addr}
- }
- if ip.To4() != nil {
- return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
- }
- // Must be IPv6
- var buf bytes.Buffer
- // Add it, in reverse, to the buffer
- for i := len(ip) - 1; i >= 0; i-- {
- s := fmt.Sprintf("%02x", ip[i])
- buf.WriteByte(s[1])
- buf.WriteByte('.')
- buf.WriteByte(s[0])
- buf.WriteByte('.')
- }
- // Append "ip6.arpa." and return (buf already has the final .)
- return buf.String() + "ip6.arpa.", nil
-}
-
-// LookupAddr performs a reverse lookup for the given address, returning a list
-// of names mapping to that address.
-func LookupAddr(addr string) (name []string, err os.Error) {
- name = lookupStaticAddr(addr)
- if len(name) > 0 {
- return
- }
- var arpa string
- arpa, err = reverseaddr(addr)
- if err != nil {
- return
- }
- var records []dnsRR
- _, records, err = lookup(arpa, dnsTypePTR)
- if err != nil {
- return
- }
- name = make([]string, len(records))
- for i := range records {
- r := records[i].(*dnsRR_PTR)
- name[i] = r.Ptr
+ s[i], s[j] = s[j], s[i]
}
- return
+ sort.Sort(s)
}
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go
new file mode 100644
index 00000000000..f407b177830
--- /dev/null
+++ b/libgo/go/net/dnsclient_unix.go
@@ -0,0 +1,261 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DNS client: see RFC 1035.
+// Has to be linked into package net for Dial.
+
+// TODO(rsc):
+// Check periodically whether /etc/resolv.conf has changed.
+// Could potentially handle many outstanding lookups faster.
+// Could have a small cache.
+// Random UDP source port (net.Dial should do that for us).
+// Random request IDs.
+
+package net
+
+import (
+ "os"
+ "rand"
+ "sync"
+ "time"
+)
+
+// Send a request on the connection and hope for a reply.
+// Up to cfg.attempts attempts.
+func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Error) {
+ if len(name) >= 256 {
+ return nil, &DNSError{Error: "name too long", Name: name}
+ }
+ out := new(dnsMsg)
+ out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
+ out.question = []dnsQuestion{
+ {name, qtype, dnsClassINET},
+ }
+ out.recursion_desired = true
+ msg, ok := out.Pack()
+ if !ok {
+ return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+ }
+
+ for attempt := 0; attempt < cfg.attempts; attempt++ {
+ n, err := c.Write(msg)
+ if err != nil {
+ return nil, err
+ }
+
+ c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
+
+ buf := make([]byte, 2000) // More than enough.
+ n, err = c.Read(buf)
+ if err != nil {
+ if e, ok := err.(Error); ok && e.Timeout() {
+ continue
+ }
+ return nil, err
+ }
+ buf = buf[0:n]
+ in := new(dnsMsg)
+ if !in.Unpack(buf) || in.id != out.id {
+ continue
+ }
+ return in, nil
+ }
+ var server string
+ if a := c.RemoteAddr(); a != nil {
+ server = a.String()
+ }
+ return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+}
+
+// Do a lookup for a single name, which must be rooted
+// (otherwise answer will not find the answers).
+func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ if len(cfg.servers) == 0 {
+ return "", nil, &DNSError{Error: "no DNS servers", Name: name}
+ }
+ for i := 0; i < len(cfg.servers); i++ {
+ // Calling Dial here is scary -- we have to be sure
+ // not to dial a name that will require a DNS lookup,
+ // or Dial will call back here to translate it.
+ // The DNS config parser has already checked that
+ // all the cfg.servers[i] are IP addresses, which
+ // Dial will use without a DNS lookup.
+ server := cfg.servers[i] + ":53"
+ c, cerr := Dial("udp", server)
+ if cerr != nil {
+ err = cerr
+ continue
+ }
+ msg, merr := exchange(cfg, c, name, qtype)
+ c.Close()
+ if merr != nil {
+ err = merr
+ continue
+ }
+ cname, addrs, err = answer(name, server, msg, qtype)
+ if err == nil || err.(*DNSError).Error == noSuchHost {
+ break
+ }
+ }
+ return
+}
+
+func convertRR_A(records []dnsRR) []IP {
+ addrs := make([]IP, len(records))
+ for i, rr := range records {
+ a := rr.(*dnsRR_A).A
+ addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
+ }
+ return addrs
+}
+
+func convertRR_AAAA(records []dnsRR) []IP {
+ addrs := make([]IP, len(records))
+ for i, rr := range records {
+ a := make(IP, 16)
+ copy(a, rr.(*dnsRR_AAAA).AAAA[:])
+ addrs[i] = a
+ }
+ return addrs
+}
+
+var cfg *dnsConfig
+var dnserr os.Error
+
+func loadConfig() { cfg, dnserr = dnsReadConfig() }
+
+var onceLoadConfig sync.Once
+
+func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ if !isDomainName(name) {
+ return name, nil, &DNSError{Error: "invalid domain name", Name: name}
+ }
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ // If name is rooted (trailing dot) or has enough dots,
+ // try it by itself first.
+ rooted := len(name) > 0 && name[len(name)-1] == '.'
+ if rooted || count(name, '.') >= cfg.ndots {
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ // Can try as ordinary name.
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ }
+ if rooted {
+ return
+ }
+
+ // Otherwise, try suffixes.
+ for i := 0; i < len(cfg.search); i++ {
+ rname := name + "." + cfg.search[i]
+ if rname[len(rname)-1] != '.' {
+ rname += "."
+ }
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ }
+
+ // Last ditch effort: try unsuffixed.
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ return
+}
+
+// goLookupHost is the native Go implementation of LookupHost.
+// Used only if cgoLookupHost refuses to handle the request
+// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupHost(name string) (addrs []string, err os.Error) {
+ // Use entries from /etc/hosts if they match.
+ addrs = lookupStaticHost(name)
+ if len(addrs) > 0 {
+ return
+ }
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ ips, err := goLookupIP(name)
+ if err != nil {
+ return
+ }
+ addrs = make([]string, 0, len(ips))
+ for _, ip := range ips {
+ addrs = append(addrs, ip.String())
+ }
+ return
+}
+
+// goLookupIP is the native Go implementation of LookupIP.
+// Used only if cgoLookupIP refuses to handle the request
+// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupIP(name string) (addrs []IP, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ var records []dnsRR
+ var cname string
+ cname, records, err = lookup(name, dnsTypeA)
+ if err != nil {
+ return
+ }
+ addrs = convertRR_A(records)
+ if cname != "" {
+ name = cname
+ }
+ _, records, err = lookup(name, dnsTypeAAAA)
+ if err != nil && len(addrs) > 0 {
+ // Ignore error because A lookup succeeded.
+ err = nil
+ }
+ if err != nil {
+ return
+ }
+ addrs = append(addrs, convertRR_AAAA(records)...)
+ return
+}
+
+// goLookupCNAME is the native Go implementation of LookupCNAME.
+// Used only if cgoLookupCNAME refuses to handle the request
+// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupCNAME(name string) (cname string, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ _, rr, err := lookup(name, dnsTypeCNAME)
+ if err != nil {
+ return
+ }
+ cname = rr[0].(*dnsRR_CNAME).Cname
+ return
+}
diff --git a/libgo/go/net/dnsconfig.go b/libgo/go/net/dnsconfig.go
index 26f0e04e907..54e334342ad 100644
--- a/libgo/go/net/dnsconfig.go
+++ b/libgo/go/net/dnsconfig.go
@@ -30,7 +30,6 @@ func (e *DNSConfigError) String() 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.
diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go
index 731efe26a44..7595aa2ab59 100644
--- a/libgo/go/net/dnsmsg.go
+++ b/libgo/go/net/dnsmsg.go
@@ -93,7 +93,7 @@ const (
// DNS queries.
type dnsQuestion struct {
- Name string "domain-name" // "domain-name" specifies encoding; see packers below
+ Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
Qtype uint16
Qclass uint16
}
@@ -102,7 +102,7 @@ type dnsQuestion struct {
// There are many types of messages,
// but they all share the same header.
type dnsRR_Header struct {
- Name string "domain-name"
+ Name string `net:"domain-name"`
Rrtype uint16
Class uint16
Ttl uint32
@@ -117,12 +117,11 @@ 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"
+ Cname string `net:"domain-name"`
}
func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
@@ -141,7 +140,7 @@ func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
type dnsRR_MB struct {
Hdr dnsRR_Header
- Mb string "domain-name"
+ Mb string `net:"domain-name"`
}
func (rr *dnsRR_MB) Header() *dnsRR_Header {
@@ -150,7 +149,7 @@ func (rr *dnsRR_MB) Header() *dnsRR_Header {
type dnsRR_MG struct {
Hdr dnsRR_Header
- Mg string "domain-name"
+ Mg string `net:"domain-name"`
}
func (rr *dnsRR_MG) Header() *dnsRR_Header {
@@ -159,8 +158,8 @@ func (rr *dnsRR_MG) Header() *dnsRR_Header {
type dnsRR_MINFO struct {
Hdr dnsRR_Header
- Rmail string "domain-name"
- Email string "domain-name"
+ Rmail string `net:"domain-name"`
+ Email string `net:"domain-name"`
}
func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
@@ -169,7 +168,7 @@ func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
type dnsRR_MR struct {
Hdr dnsRR_Header
- Mr string "domain-name"
+ Mr string `net:"domain-name"`
}
func (rr *dnsRR_MR) Header() *dnsRR_Header {
@@ -179,7 +178,7 @@ func (rr *dnsRR_MR) Header() *dnsRR_Header {
type dnsRR_MX struct {
Hdr dnsRR_Header
Pref uint16
- Mx string "domain-name"
+ Mx string `net:"domain-name"`
}
func (rr *dnsRR_MX) Header() *dnsRR_Header {
@@ -188,7 +187,7 @@ func (rr *dnsRR_MX) Header() *dnsRR_Header {
type dnsRR_NS struct {
Hdr dnsRR_Header
- Ns string "domain-name"
+ Ns string `net:"domain-name"`
}
func (rr *dnsRR_NS) Header() *dnsRR_Header {
@@ -197,7 +196,7 @@ func (rr *dnsRR_NS) Header() *dnsRR_Header {
type dnsRR_PTR struct {
Hdr dnsRR_Header
- Ptr string "domain-name"
+ Ptr string `net:"domain-name"`
}
func (rr *dnsRR_PTR) Header() *dnsRR_Header {
@@ -206,8 +205,8 @@ func (rr *dnsRR_PTR) Header() *dnsRR_Header {
type dnsRR_SOA struct {
Hdr dnsRR_Header
- Ns string "domain-name"
- Mbox string "domain-name"
+ Ns string `net:"domain-name"`
+ Mbox string `net:"domain-name"`
Serial uint32
Refresh uint32
Retry uint32
@@ -233,7 +232,7 @@ type dnsRR_SRV struct {
Priority uint16
Weight uint16
Port uint16
- Target string "domain-name"
+ Target string `net:"domain-name"`
}
func (rr *dnsRR_SRV) Header() *dnsRR_Header {
@@ -242,7 +241,7 @@ func (rr *dnsRR_SRV) Header() *dnsRR_Header {
type dnsRR_A struct {
Hdr dnsRR_Header
- A uint32 "ipv4"
+ A uint32 `net:"ipv4"`
}
func (rr *dnsRR_A) Header() *dnsRR_Header {
@@ -251,7 +250,7 @@ func (rr *dnsRR_A) Header() *dnsRR_Header {
type dnsRR_AAAA struct {
Hdr dnsRR_Header
- AAAA [16]byte "ipv6"
+ AAAA [16]byte `net:"ipv6"`
}
func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
@@ -395,7 +394,6 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
f := val.Type().Field(i)
switch fv := val.Field(i); fv.Kind() {
default:
- BadType:
fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
return len(msg), false
case reflect.Struct:
@@ -420,7 +418,8 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
off += 4
case reflect.Array:
if fv.Type().Elem().Kind() != reflect.Uint8 {
- goto BadType
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
}
n := fv.Len()
if off+n > len(msg) {
@@ -436,7 +435,7 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
default:
fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
return len(msg), false
- case "domain-name":
+ case `net:"domain-name"`:
off, ok = packDomainName(s, msg, off)
if !ok {
return len(msg), false
@@ -472,7 +471,6 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
f := val.Type().Field(i)
switch fv := val.Field(i); fv.Kind() {
default:
- BadType:
fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
return len(msg), false
case reflect.Struct:
@@ -493,7 +491,8 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
off += 4
case reflect.Array:
if fv.Type().Elem().Kind() != reflect.Uint8 {
- goto BadType
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
}
n := fv.Len()
if off+n > len(msg) {
@@ -507,7 +506,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
default:
fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
return len(msg), false
- case "domain-name":
+ case `net:"domain-name"`:
s, off, ok = unpackDomainName(msg, off)
if !ok {
return len(msg), false
@@ -537,9 +536,9 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
}
// Generic struct printer.
-// Doesn't care about the string tag "domain-name",
-// but does look for an "ipv4" tag on uint32 variables
-// and the "ipv6" tag on array variables,
+// Doesn't care about the string tag `net:"domain-name"`,
+// but does look for an `net:"ipv4"` tag on uint32 variables
+// and the `net:"ipv6"` tag on array variables,
// printing them as IP addresses.
func printStructValue(val reflect.Value) string {
s := "{"
@@ -554,10 +553,10 @@ func printStructValue(val reflect.Value) string {
fval := val.Field(i)
if fv := fval; fv.Kind() == reflect.Struct {
s += printStructValue(fv)
- } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == "ipv4" {
+ } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == `net:"ipv4"` {
i := fv.Uint()
s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
- } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == "ipv6" {
+ } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == `net:"ipv6"` {
i := fv.Interface().([]byte)
s += IP(i).String()
} else {
@@ -636,7 +635,6 @@ type dnsMsg struct {
extra []dnsRR
}
-
func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
var dh dnsHeader
diff --git a/libgo/go/net/dnsmsg_test.go b/libgo/go/net/dnsmsg_test.go
index 20c9f02b0b4..06152a01a23 100644
--- a/libgo/go/net/dnsmsg_test.go
+++ b/libgo/go/net/dnsmsg_test.go
@@ -6,14 +6,10 @@ package net
import (
"encoding/hex"
- "runtime"
"testing"
)
func TestDNSParseSRVReply(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
data, err := hex.DecodeString(dnsSRVReply)
if err != nil {
t.Fatal(err)
@@ -45,9 +41,6 @@ func TestDNSParseSRVReply(t *testing.T) {
}
func TestDNSParseCorruptSRVReply(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
data, err := hex.DecodeString(dnsSRVCorruptReply)
if err != nil {
t.Fatal(err)
diff --git a/libgo/go/net/dnsname_test.go b/libgo/go/net/dnsname_test.go
index 0c1a6251899..70df693f789 100644
--- a/libgo/go/net/dnsname_test.go
+++ b/libgo/go/net/dnsname_test.go
@@ -6,7 +6,6 @@ package net
import (
"testing"
- "runtime"
)
type testCase struct {
@@ -55,9 +54,6 @@ func getTestCases(ch chan<- testCase) {
}
func TestDNSNames(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
ch := make(chan testCase)
go getTestCases(ch)
for tc := range ch {
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
index cd1a21dc361..707dccaa421 100644
--- a/libgo/go/net/fd.go
+++ b/libgo/go/net/fd.go
@@ -585,20 +585,25 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
fd.incref()
defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
// See ../syscall/exec.go for description of ForkLock.
// It is okay to hold the lock across syscall.Accept
// because we have put fd.sysfd into non-blocking mode.
syscall.ForkLock.RLock()
var s, e int
- var sa syscall.Sockaddr
+ var rsa syscall.Sockaddr
for {
if fd.closing {
syscall.ForkLock.RUnlock()
return nil, os.EINVAL
}
- s, sa, e = syscall.Accept(fd.sysfd)
- if e != syscall.EAGAIN {
+ s, rsa, e = syscall.Accept(fd.sysfd)
+ if e != syscall.EAGAIN || fd.rdeadline < 0 {
break
}
syscall.ForkLock.RUnlock()
@@ -616,7 +621,8 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
syscall.Close(s)
return nil, err
}
- nfd.setAddr(fd.laddr, toAddr(sa))
+ lsa, _ := syscall.Getsockname(nfd.sysfd)
+ nfd.setAddr(toAddr(lsa), toAddr(rsa))
return nfd, nil
}
diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go
index dcf65c014d5..70fc344b2a0 100644
--- a/libgo/go/net/fd_linux.go
+++ b/libgo/go/net/fd_linux.go
@@ -117,6 +117,17 @@ func (p *pollster) DelFD(fd int, mode int) {
} else {
p.StopWaiting(fd, writeFlags)
}
+
+ // Discard any queued up events.
+ i := 0
+ for i < len(p.waitEvents) {
+ if fd == int(p.waitEvents[i].Fd) {
+ copy(p.waitEvents[i:], p.waitEvents[i+1:])
+ p.waitEvents = p.waitEvents[:len(p.waitEvents)-1]
+ } else {
+ i++
+ }
+ }
}
func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
diff --git a/libgo/go/net/fd_openbsd.go b/libgo/go/net/fd_openbsd.go
new file mode 100644
index 00000000000..e50883e940b
--- /dev/null
+++ b/libgo/go/net/fd_openbsd.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.
+
+// Waiting for FDs via kqueue/kevent.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+type pollster struct {
+ kq int
+ eventbuf [10]syscall.Kevent_t
+ events []syscall.Kevent_t
+
+ // An event buffer for AddFD/DelFD.
+ // Must hold pollServer lock.
+ kbuf [1]syscall.Kevent_t
+}
+
+func newpollster() (p *pollster, err os.Error) {
+ p = new(pollster)
+ var e int
+ if p.kq, e = syscall.Kqueue(); e != 0 {
+ return nil, os.NewSyscallError("kqueue", e)
+ }
+ p.events = p.eventbuf[0:0]
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_ADD - add event to kqueue list
+ // EV_ONESHOT - delete the event the first time it triggers
+ flags := syscall.EV_ADD
+ if !repeat {
+ flags |= syscall.EV_ONESHOT
+ }
+ syscall.SetKevent(ev, fd, kmode, flags)
+
+ n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+ if e != 0 {
+ return false, os.NewSyscallError("kevent", e)
+ }
+ if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+ return false, os.NewSyscallError("kqueue phase error", e)
+ }
+ if ev.Data != 0 {
+ return false, os.Errno(int(ev.Data))
+ }
+ return false, nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_DELETE - delete event from kqueue list
+ syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
+ syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+ var t *syscall.Timespec
+ for len(p.events) == 0 {
+ if nsec > 0 {
+ if t == nil {
+ t = new(syscall.Timespec)
+ }
+ *t = syscall.NsecToTimespec(nsec)
+ }
+
+ s.Unlock()
+ nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+ s.Lock()
+
+ if e != 0 {
+ if e == syscall.EINTR {
+ continue
+ }
+ return -1, 0, os.NewSyscallError("kevent", e)
+ }
+ if nn == 0 {
+ return -1, 0, nil
+ }
+ p.events = p.eventbuf[0:nn]
+ }
+ ev := &p.events[0]
+ p.events = p.events[1:]
+ fd = int(ev.Ident)
+ if ev.Filter == syscall.EVFILT_READ {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ return fd, mode, nil
+}
+
+func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index c2f736cc126..3757e143dca 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -29,8 +29,8 @@ func init() {
}
}
-func closesocket(s int) (errno int) {
- return syscall.Closesocket(int32(s))
+func closesocket(s syscall.Handle) (errno int) {
+ return syscall.Closesocket(s)
}
// Interface for all io operations.
@@ -84,11 +84,11 @@ func (o *bufOp) Init(fd *netFD, buf []byte) {
}
}
-// resultSrv will retreive all io completion results from
+// resultSrv will retrieve all io completion results from
// iocp and send them to the correspondent waiting client
// goroutine via channel supplied in the request.
type resultSrv struct {
- iocp int32
+ iocp syscall.Handle
}
func (s *resultSrv) Run() {
@@ -113,7 +113,6 @@ func (s *resultSrv) Run() {
}
}
-
// ioSrv executes net io requests.
type ioSrv struct {
submchan chan anOpIface // submit io requests
@@ -132,7 +131,7 @@ func (s *ioSrv) ProcessRemoteIO() {
case o := <-s.submchan:
o.Op().errnoc <- o.Submit()
case o := <-s.canchan:
- o.Op().errnoc <- syscall.CancelIo(uint32(o.Op().fd.sysfd))
+ o.Op().errnoc <- syscall.CancelIo(syscall.Handle(o.Op().fd.sysfd))
}
}
}
@@ -155,7 +154,7 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error)
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.
+ // IO started, and we have to wait for its completion.
default:
return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)}
}
@@ -189,7 +188,7 @@ var onceStartServer sync.Once
func startServer() {
resultsrv = new(resultSrv)
var errno int
- resultsrv.iocp, errno = syscall.CreateIoCompletionPort(-1, 0, 0, 1)
+ resultsrv.iocp, errno = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
if errno != 0 {
panic("CreateIoCompletionPort failed " + syscall.Errstr(errno))
}
@@ -209,7 +208,7 @@ type netFD struct {
closing bool
// immutable until Close
- sysfd int
+ sysfd syscall.Handle
family int
proto int
net string
@@ -225,7 +224,7 @@ type netFD struct {
wio sync.Mutex
}
-func allocFD(fd, family, proto int, net string) (f *netFD) {
+func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) {
f = &netFD{
sysfd: fd,
family: family,
@@ -236,13 +235,13 @@ func allocFD(fd, family, proto int, net string) (f *netFD) {
return f
}
-func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
+func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err os.Error) {
if initErr != nil {
return nil, initErr
}
onceStartServer.Do(startServer)
// Associate our socket with resultsrv.iocp.
- if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 {
+ if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != 0 {
return nil, os.Errno(e)
}
return allocFD(fd, family, proto, net), nil
@@ -273,14 +272,14 @@ func (fd *netFD) incref() {
func (fd *netFD) decref() {
fd.sysmu.Lock()
fd.sysref--
- if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
+ if fd.closing && fd.sysref == 0 && fd.sysfd != syscall.InvalidHandle {
// 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 resultsrv for Close too. Sigh.
syscall.SetNonblock(fd.sysfd, false)
closesocket(fd.sysfd)
- fd.sysfd = -1
+ fd.sysfd = syscall.InvalidHandle
// no need for a finalizer anymore
runtime.SetFinalizer(fd, nil)
}
@@ -288,7 +287,7 @@ func (fd *netFD) decref() {
}
func (fd *netFD) Close() os.Error {
- if fd == nil || fd.sysfd == -1 {
+ if fd == nil || fd.sysfd == syscall.InvalidHandle {
return os.EINVAL
}
@@ -307,7 +306,7 @@ type readOp struct {
func (o *readOp) Submit() (errno int) {
var d, f uint32
- return syscall.WSARecv(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
+ return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
}
func (o *readOp) Name() string {
@@ -322,7 +321,7 @@ func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
defer fd.rio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfd == -1 {
+ if fd.sysfd == syscall.InvalidHandle {
return 0, os.EINVAL
}
var o readOp
@@ -338,13 +337,13 @@ func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
type readFromOp struct {
bufOp
- rsa syscall.RawSockaddrAny
+ rsa syscall.RawSockaddrAny
+ rsan int32
}
func (o *readFromOp) Submit() (errno int) {
var d, f uint32
- l := int32(unsafe.Sizeof(o.rsa))
- return syscall.WSARecvFrom(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.rsa, &l, &o.o, nil)
+ return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
}
func (o *readFromOp) Name() string {
@@ -362,12 +361,16 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error)
defer fd.rio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfd == -1 {
+ if fd.sysfd == syscall.InvalidHandle {
return 0, nil, os.EINVAL
}
var o readFromOp
o.Init(fd, buf)
+ o.rsan = int32(unsafe.Sizeof(o.rsa))
n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ if err != nil {
+ return 0, nil, err
+ }
sa, _ = o.rsa.Sockaddr()
return
}
@@ -380,7 +383,7 @@ type writeOp struct {
func (o *writeOp) Submit() (errno int) {
var d uint32
- return syscall.WSASend(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, &o.o, nil)
+ return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
}
func (o *writeOp) Name() string {
@@ -395,7 +398,7 @@ func (fd *netFD) Write(buf []byte) (n int, err os.Error) {
defer fd.wio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfd == -1 {
+ if fd.sysfd == syscall.InvalidHandle {
return 0, os.EINVAL
}
var o writeOp
@@ -412,7 +415,7 @@ type writeToOp struct {
func (o *writeToOp) Submit() (errno int) {
var d uint32
- return syscall.WSASendto(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, o.sa, &o.o, nil)
+ return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
}
func (o *writeToOp) Name() string {
@@ -430,7 +433,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error)
defer fd.wio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfd == -1 {
+ if fd.sysfd == syscall.InvalidHandle {
return 0, os.EINVAL
}
var o writeToOp
@@ -443,14 +446,14 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error)
type acceptOp struct {
anOp
- newsock int
+ newsock syscall.Handle
attrs [2]syscall.RawSockaddrAny // space for local and remote address only
}
func (o *acceptOp) Submit() (errno int) {
var d uint32
l := uint32(unsafe.Sizeof(o.attrs[0]))
- return syscall.AcceptEx(uint32(o.fd.sysfd), uint32(o.newsock),
+ return syscall.AcceptEx(o.fd.sysfd, o.newsock,
(*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o)
}
@@ -459,7 +462,7 @@ func (o *acceptOp) Name() string {
}
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
- if fd == nil || fd.sysfd == -1 {
+ if fd == nil || fd.sysfd == syscall.InvalidHandle {
return nil, os.EINVAL
}
fd.incref()
@@ -478,7 +481,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
// Associate our new socket with IOCP.
onceStartServer.Do(startServer)
- if _, e = syscall.CreateIoCompletionPort(int32(s), resultsrv.iocp, 0, 0); e != 0 {
+ if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != 0 {
return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
}
@@ -493,7 +496,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
}
// Inherit properties of the listening socket.
- e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
+ e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
if e != 0 {
closesocket(s)
return nil, err
@@ -513,7 +516,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
return nfd, nil
}
-// Not implemeted functions.
+// Unimplemented functions.
func (fd *netFD) dup() (f *os.File, err os.Error) {
// TODO: Implement this
diff --git a/libgo/go/net/file_plan9.go b/libgo/go/net/file_plan9.go
new file mode 100644
index 00000000000..a07e7433181
--- /dev/null
+++ b/libgo/go/net/file_plan9.go
@@ -0,0 +1,33 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+)
+
+// FileConn returns a copy of the network connection corresponding to
+// the open file f. 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 FileConn(f *os.File) (c Conn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f. It is the caller's responsibility to close l
+// when finished. Closing c does not affect l, and closing l does not
+// affect c.
+func FileListener(f *os.File) (l Listener, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f. 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 FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
+ return nil, os.EPLAN9
+}
diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go
index 1ec05fdeea5..9a8c2dcbc4c 100644
--- a/libgo/go/net/file_test.go
+++ b/libgo/go/net/file_test.go
@@ -57,12 +57,12 @@ func testFileListener(t *testing.T, net, laddr string) {
}
func TestFileListener(t *testing.T) {
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
testFileListener(t, "tcp", "127.0.0.1")
testFileListener(t, "tcp", "127.0.0.1")
- if kernelSupportsIPv6() {
+ if supportsIPv6 && supportsIPv4map {
testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
testFileListener(t, "tcp", "127.0.0.1")
testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
@@ -116,13 +116,15 @@ func testFilePacketConnDial(t *testing.T, net, raddr string) {
}
func TestFilePacketConn(t *testing.T) {
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
testFilePacketConnListen(t, "udp", "127.0.0.1:0")
testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
- if kernelSupportsIPv6() {
+ if supportsIPv6 {
testFilePacketConnListen(t, "udp", "[::1]:0")
+ }
+ if supportsIPv6 && supportsIPv4map {
testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
}
if syscall.OS == "linux" {
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
index e5793eef2c7..1bd00541c6d 100644
--- a/libgo/go/net/hosts_test.go
+++ b/libgo/go/net/hosts_test.go
@@ -59,7 +59,7 @@ func TestLookupHost(t *testing.T) {
// duplicate addresses (a common bug due to the way
// getaddrinfo works).
addrs, _ := LookupHost("localhost")
- sort.SortStrings(addrs)
+ sort.Strings(addrs)
for i := 0; i+1 < len(addrs); i++ {
if addrs[i] == addrs[i+1] {
t.Fatalf("LookupHost(\"localhost\") = %v, has duplicate addresses", addrs)
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go
new file mode 100644
index 00000000000..8a14cb23202
--- /dev/null
+++ b/libgo/go/net/interface.go
@@ -0,0 +1,132 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification
+
+package net
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+)
+
+// A HardwareAddr represents a physical hardware address.
+type HardwareAddr []byte
+
+func (a HardwareAddr) String() string {
+ var buf bytes.Buffer
+ for i, b := range a {
+ if i > 0 {
+ buf.WriteByte(':')
+ }
+ fmt.Fprintf(&buf, "%02x", b)
+ }
+ return buf.String()
+}
+
+// Interface represents a mapping between network interface name
+// and index. It also represents network interface facility
+// information.
+type Interface struct {
+ Index int // positive integer that starts at one, zero is never used
+ MTU int // maximum transmission unit
+ Name string // e.g., "en0", "lo0", "eth0.100"
+ HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
+ Flags Flags // e.g., FlagUp, FlagLoopback, FlagMulticast
+}
+
+type Flags uint
+
+const (
+ FlagUp Flags = 1 << iota // interface is up
+ FlagBroadcast // interface supports broadcast access capability
+ FlagLoopback // interface is a loopback interface
+ FlagPointToPoint // interface belongs to a point-to-point link
+ FlagMulticast // interface supports multicast access capability
+)
+
+var flagNames = []string{
+ "up",
+ "broadcast",
+ "loopback",
+ "pointtopoint",
+ "multicast",
+}
+
+func (f Flags) String() string {
+ s := ""
+ for i, name := range flagNames {
+ if f&(1<<uint(i)) != 0 {
+ if s != "" {
+ s += "|"
+ }
+ s += name
+ }
+ }
+ if s == "" {
+ s = "0"
+ }
+ return s
+}
+
+// Addrs returns interface addresses for a specific interface.
+func (ifi *Interface) Addrs() ([]Addr, os.Error) {
+ if ifi == nil {
+ return nil, os.NewError("net: invalid interface")
+ }
+ return interfaceAddrTable(ifi.Index)
+}
+
+// MulticastAddrs returns multicast, joined group addresses for
+// a specific interface.
+func (ifi *Interface) MulticastAddrs() ([]Addr, os.Error) {
+ if ifi == nil {
+ return nil, os.NewError("net: invalid interface")
+ }
+ return interfaceMulticastAddrTable(ifi.Index)
+}
+
+// Interfaces returns a list of the systems's network interfaces.
+func Interfaces() ([]Interface, os.Error) {
+ return interfaceTable(0)
+}
+
+// InterfaceAddrs returns a list of the system's network interface
+// addresses.
+func InterfaceAddrs() ([]Addr, os.Error) {
+ return interfaceAddrTable(0)
+}
+
+// InterfaceByIndex returns the interface specified by index.
+func InterfaceByIndex(index int) (*Interface, os.Error) {
+ if index <= 0 {
+ return nil, os.NewError("net: invalid interface index")
+ }
+ ift, err := interfaceTable(index)
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ return &ifi, nil
+ }
+ return nil, os.NewError("net: no such interface")
+}
+
+// InterfaceByName returns the interface specified by name.
+func InterfaceByName(name string) (*Interface, os.Error) {
+ if name == "" {
+ return nil, os.NewError("net: invalid interface name")
+ }
+ ift, err := interfaceTable(0)
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ if name == ifi.Name {
+ return &ifi, nil
+ }
+ }
+ return nil, os.NewError("net: no such interface")
+}
diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go
new file mode 100644
index 00000000000..2675f94b973
--- /dev/null
+++ b/libgo/go/net/interface_bsd.go
@@ -0,0 +1,171 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for BSD variants
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ift []Interface
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifi, err := newLink(v)
+ if err != nil {
+ return nil, err
+ }
+ ift = append(ift, ifi...)
+ }
+ }
+ }
+
+ return ift, nil
+}
+
+func newLink(m *syscall.InterfaceMessage) ([]Interface, os.Error) {
+ var ift []Interface
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ switch v := s.(type) {
+ case *syscall.SockaddrDatalink:
+ // NOTE: SockaddrDatalink.Data is minimum work area,
+ // can be larger.
+ m.Data = m.Data[unsafe.Offsetof(v.Data):]
+ ifi := Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
+ var name [syscall.IFNAMSIZ]byte
+ for i := 0; i < int(v.Nlen); i++ {
+ name[i] = byte(m.Data[i])
+ }
+ ifi.Name = string(name[:v.Nlen])
+ ifi.MTU = int(m.Header.Data.Mtu)
+ addr := make([]byte, v.Alen)
+ for i := 0; i < int(v.Alen); i++ {
+ addr[i] = byte(m.Data[int(v.Nlen)+i])
+ }
+ ifi.HardwareAddr = addr[:v.Alen]
+ ift = append(ift, ifi)
+ }
+ }
+
+ return ift, nil
+}
+
+func linkFlags(rawFlags int32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifa, err := newAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifat = append(ifat, ifa...)
+ }
+ }
+ }
+
+ return ifat, nil
+}
+
+func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, os.Error) {
+ var ifat []Addr
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+
+ switch v := s.(type) {
+ case *syscall.SockaddrInet4:
+ ifa := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+ ifat = append(ifat, ifa.toAddr())
+ case *syscall.SockaddrInet6:
+ ifa := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifa.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifa.IP.IsLinkLocalUnicast() {
+ // remove embedded scope zone ID
+ ifa.IP[2], ifa.IP[3] = 0, 0
+ }
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+
+ return ifat, nil
+}
diff --git a/libgo/go/net/interface_darwin.go b/libgo/go/net/interface_darwin.go
new file mode 100644
index 00000000000..a7b68ad7f77
--- /dev/null
+++ b/libgo/go/net/interface_darwin.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for Darwin
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifmat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMulticastAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifma, err := newMulticastAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifmat = append(ifmat, ifma...)
+ }
+ }
+ }
+
+ return ifmat, nil
+}
+
+func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, os.Error) {
+ var ifmat []Addr
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ switch v := s.(type) {
+ case *syscall.SockaddrInet4:
+ ifma := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+ ifmat = append(ifmat, ifma.toAddr())
+ case *syscall.SockaddrInet6:
+ ifma := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifma.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifma.IP.IsInterfaceLocalMulticast() ||
+ ifma.IP.IsLinkLocalMulticast() {
+ // remove embedded scope zone ID
+ ifma.IP[2], ifma.IP[3] = 0, 0
+ }
+ ifmat = append(ifmat, ifma.toAddr())
+ }
+ }
+
+ return ifmat, nil
+}
diff --git a/libgo/go/net/interface_freebsd.go b/libgo/go/net/interface_freebsd.go
new file mode 100644
index 00000000000..20f506b08bc
--- /dev/null
+++ b/libgo/go/net/interface_freebsd.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for FreeBSD
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifmat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMulticastAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifma, err := newMulticastAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifmat = append(ifmat, ifma...)
+ }
+ }
+ }
+
+ return ifmat, nil
+}
+
+func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, os.Error) {
+ var ifmat []Addr
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ switch v := s.(type) {
+ case *syscall.SockaddrInet4:
+ ifma := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+ ifmat = append(ifmat, ifma.toAddr())
+ case *syscall.SockaddrInet6:
+ ifma := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifma.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifma.IP.IsInterfaceLocalMulticast() ||
+ ifma.IP.IsLinkLocalMulticast() {
+ // remove embedded scope zone ID
+ ifma.IP[2], ifma.IP[3] = 0, 0
+ }
+ ifmat = append(ifmat, ifma.toAddr())
+ }
+ }
+
+ return ifmat, nil
+}
diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go
new file mode 100644
index 00000000000..3d2a0bb9f8a
--- /dev/null
+++ b/libgo/go/net/interface_linux.go
@@ -0,0 +1,262 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for Linux
+
+package net
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ var (
+ ift []Interface
+ tab []byte
+ msgs []syscall.NetlinkMessage
+ e int
+ )
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+
+ msgs, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ goto done
+ case syscall.RTM_NEWLINK:
+ ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
+ if ifindex == 0 || ifindex == int(ifim.Index) {
+ attrs, e := syscall.ParseNetlinkRouteAttr(&m)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink routeattr", e)
+ }
+ ifi := newLink(attrs, ifim)
+ ift = append(ift, ifi)
+ }
+ }
+ }
+
+done:
+ return ift, nil
+}
+
+func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
+ ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.IFLA_ADDRESS:
+ var nonzero bool
+ for _, b := range a.Value {
+ if b != 0 {
+ nonzero = true
+ }
+ }
+ if nonzero {
+ ifi.HardwareAddr = a.Value[:]
+ }
+ case syscall.IFLA_IFNAME:
+ ifi.Name = string(a.Value[:len(a.Value)-1])
+ case syscall.IFLA_MTU:
+ ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
+ }
+ }
+ return ifi
+}
+
+func linkFlags(rawFlags uint32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ err os.Error
+ ifat4 []Addr
+ ifat6 []Addr
+ msgs4 []syscall.NetlinkMessage
+ msgs6 []syscall.NetlinkMessage
+ )
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+ msgs4, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+ ifat4, err = addrTable(msgs4, ifindex)
+ if err != nil {
+ return nil, err
+ }
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET6)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+ msgs6, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+ ifat6, err = addrTable(msgs6, ifindex)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(ifat4, ifat6...), nil
+}
+
+func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, os.Error) {
+ var ifat []Addr
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ goto done
+ case syscall.RTM_NEWADDR:
+ ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
+ if ifindex == 0 || ifindex == int(ifam.Index) {
+ attrs, e := syscall.ParseNetlinkRouteAttr(&m)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink routeattr", e)
+ }
+ ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
+ }
+ }
+ }
+
+done:
+ return ifat, nil
+}
+
+func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
+ var ifat []Addr
+
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.IFA_ADDRESS:
+ switch family {
+ case syscall.AF_INET:
+ ifa := &IPAddr{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])}
+ ifat = append(ifat, ifa.toAddr())
+ case syscall.AF_INET6:
+ ifa := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifa.IP, a.Value[:])
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+ }
+
+ return ifat
+}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ ifi *Interface
+ err os.Error
+ )
+
+ if ifindex > 0 {
+ ifi, err = InterfaceByIndex(ifindex)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ ifmat4 := parseProcNetIGMP(ifi)
+ ifmat6 := parseProcNetIGMP6(ifi)
+
+ return append(ifmat4, ifmat6...), nil
+}
+
+func parseProcNetIGMP(ifi *Interface) []Addr {
+ var (
+ ifmat []Addr
+ name string
+ )
+
+ fd, err := open("/proc/net/igmp")
+ if err != nil {
+ return nil
+ }
+ defer fd.close()
+
+ fd.readLine() // skip first line
+ b := make([]byte, IPv4len)
+ for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
+ f := getFields(l)
+ switch len(f) {
+ case 4:
+ if ifi == nil || name == ifi.Name {
+ fmt.Sscanf(f[0], "%08x", &b)
+ ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
+ ifmat = append(ifmat, ifma.toAddr())
+ }
+ case 5:
+ name = f[1]
+ }
+ }
+
+ return ifmat
+}
+
+func parseProcNetIGMP6(ifi *Interface) []Addr {
+ var ifmat []Addr
+
+ fd, err := open("/proc/net/igmp6")
+ if err != nil {
+ return nil
+ }
+ defer fd.close()
+
+ b := make([]byte, IPv6len)
+ for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
+ f := getFields(l)
+ if ifi == nil || f[1] == ifi.Name {
+ fmt.Sscanf(f[2], "%32x", &b)
+ ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
+ ifmat = append(ifmat, ifma.toAddr())
+
+ }
+ }
+
+ return ifmat
+}
diff --git a/libgo/go/net/interface_openbsd.go b/libgo/go/net/interface_openbsd.go
new file mode 100644
index 00000000000..f18149393a5
--- /dev/null
+++ b/libgo/go/net/interface_openbsd.go
@@ -0,0 +1,16 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for OpenBSD
+
+package net
+
+import "os"
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/libgo/go/net/interface_stub.go b/libgo/go/net/interface_stub.go
new file mode 100644
index 00000000000..950de6c5926
--- /dev/null
+++ b/libgo/go/net/interface_stub.go
@@ -0,0 +1,30 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification
+
+package net
+
+import "os"
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ return nil, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go
new file mode 100644
index 00000000000..0e4089abf8a
--- /dev/null
+++ b/libgo/go/net/interface_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "bytes"
+ "testing"
+)
+
+func sameInterface(i, j *Interface) bool {
+ if i == nil || j == nil {
+ return false
+ }
+ if i.Index == j.Index && i.Name == j.Name && bytes.Equal(i.HardwareAddr, j.HardwareAddr) {
+ return true
+ }
+ return false
+}
+
+func TestInterfaces(t *testing.T) {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatalf("Interfaces() failed: %v", err)
+ }
+ t.Logf("table: len/cap = %v/%v\n", len(ift), cap(ift))
+
+ for _, ifi := range ift {
+ ifxi, err := InterfaceByIndex(ifi.Index)
+ if err != nil {
+ t.Fatalf("InterfaceByIndex(%#q) failed: %v", ifi.Index, err)
+ }
+ if !sameInterface(ifxi, &ifi) {
+ t.Fatalf("InterfaceByIndex(%#q) = %v, want %v", ifi.Index, *ifxi, ifi)
+ }
+ ifxn, err := InterfaceByName(ifi.Name)
+ if err != nil {
+ t.Fatalf("InterfaceByName(%#q) failed: %v", ifi.Name, err)
+ }
+ if !sameInterface(ifxn, &ifi) {
+ t.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
+ }
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ t.Fatalf("Interface.Addrs() failed: %v", err)
+ }
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ t.Fatalf("Interface.MulticastAddrs() failed: %v", err)
+ }
+ t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
+ for _, ifa := range ifat {
+ t.Logf("\tinterface address %q\n", ifa.String())
+ }
+ for _, ifma := range ifmat {
+ t.Logf("\tjoined group address %q\n", ifma.String())
+ }
+ t.Logf("\thardware address %q", ifi.HardwareAddr.String())
+ }
+}
+
+func TestInterfaceAddrs(t *testing.T) {
+ ifat, err := InterfaceAddrs()
+ if err != nil {
+ t.Fatalf("InterfaceAddrs() failed: %v", err)
+ }
+ t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
+
+ for _, ifa := range ifat {
+ t.Logf("interface address %q\n", ifa.String())
+ }
+}
diff --git a/libgo/go/net/interface_windows.go b/libgo/go/net/interface_windows.go
new file mode 100644
index 00000000000..7f5169c8797
--- /dev/null
+++ b/libgo/go/net/interface_windows.go
@@ -0,0 +1,158 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for Windows
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func bytePtrToString(p *uint8) string {
+ a := (*[10000]uint8)(unsafe.Pointer(p))
+ i := 0
+ for a[i] != 0 {
+ i++
+ }
+ return string(a[:i])
+}
+
+func getAdapterList() (*syscall.IpAdapterInfo, os.Error) {
+ b := make([]byte, 1000)
+ l := uint32(len(b))
+ a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+ e := syscall.GetAdaptersInfo(a, &l)
+ if e == syscall.ERROR_BUFFER_OVERFLOW {
+ b = make([]byte, l)
+ a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+ e = syscall.GetAdaptersInfo(a, &l)
+ }
+ if e != 0 {
+ return nil, os.NewSyscallError("GetAdaptersInfo", e)
+ }
+ return a, nil
+}
+
+func getInterfaceList() ([]syscall.InterfaceInfo, os.Error) {
+ s, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+ if e != 0 {
+ return nil, os.NewSyscallError("Socket", e)
+ }
+ defer syscall.Closesocket(s)
+
+ ii := [20]syscall.InterfaceInfo{}
+ ret := uint32(0)
+ size := uint32(unsafe.Sizeof(ii))
+ e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+ if e != 0 {
+ return nil, os.NewSyscallError("WSAIoctl", e)
+ }
+ c := ret / uint32(unsafe.Sizeof(ii[0]))
+ return ii[:c-1], nil
+}
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ ai, e := getAdapterList()
+ if e != nil {
+ return nil, e
+ }
+
+ ii, e := getInterfaceList()
+ if e != nil {
+ return nil, e
+ }
+
+ var ift []Interface
+ for ; ai != nil; ai = ai.Next {
+ index := ai.Index
+ if ifindex == 0 || ifindex == int(index) {
+ var flags Flags
+
+ row := syscall.MibIfRow{Index: index}
+ e := syscall.GetIfEntry(&row)
+ if e != 0 {
+ return nil, os.NewSyscallError("GetIfEntry", e)
+ }
+
+ for _, ii := range ii {
+ ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
+ ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
+ ipl := &ai.IpAddressList
+ for ipl != nil {
+ ips := bytePtrToString(&ipl.IpAddress.String[0])
+ if ipv4.Equal(parseIPv4(ips)) {
+ break
+ }
+ ipl = ipl.Next
+ }
+ if ipl == nil {
+ continue
+ }
+ if ii.Flags&syscall.IFF_UP != 0 {
+ flags |= FlagUp
+ }
+ if ii.Flags&syscall.IFF_LOOPBACK != 0 {
+ flags |= FlagLoopback
+ }
+ if ii.Flags&syscall.IFF_BROADCAST != 0 {
+ flags |= FlagBroadcast
+ }
+ if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
+ flags |= FlagPointToPoint
+ }
+ if ii.Flags&syscall.IFF_MULTICAST != 0 {
+ flags |= FlagMulticast
+ }
+ }
+
+ name := bytePtrToString(&ai.AdapterName[0])
+
+ ifi := Interface{
+ Index: int(index),
+ MTU: int(row.Mtu),
+ Name: name,
+ HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
+ Flags: flags}
+ ift = append(ift, ifi)
+ }
+ }
+ return ift, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ ai, e := getAdapterList()
+ if e != nil {
+ return nil, e
+ }
+
+ var ifat []Addr
+ for ; ai != nil; ai = ai.Next {
+ index := ai.Index
+ if ifindex == 0 || ifindex == int(index) {
+ ipl := &ai.IpAddressList
+ for ; ipl != nil; ipl = ipl.Next {
+ ifa := IPAddr{}
+ ifa.IP = parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+ }
+ return ifat, nil
+}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go
index 61b2c687e2f..b0e2c42053f 100644
--- a/libgo/go/net/ip.go
+++ b/libgo/go/net/ip.go
@@ -75,10 +75,71 @@ var (
// Well-known IPv6 addresses
var (
- IPzero = make(IP, IPv6len) // all zeros
- IPv6loopback = IP([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
+ IPv6zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ IPv6unspecified = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ IPv6loopback = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+ IPv6interfacelocalallnodes = IP{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
+ IPv6linklocalallnodes = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
+ IPv6linklocalallrouters = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
)
+// IsUnspecified returns true if ip is an unspecified address.
+func (ip IP) IsUnspecified() bool {
+ if ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified) {
+ return true
+ }
+ return false
+}
+
+// IsLoopback returns true if ip is a loopback address.
+func (ip IP) IsLoopback() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 127 {
+ return true
+ }
+ return ip.Equal(IPv6loopback)
+}
+
+// IsMulticast returns true if ip is a multicast address.
+func (ip IP) IsMulticast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0]&0xf0 == 0xe0 {
+ return true
+ }
+ return ip[0] == 0xff
+}
+
+// IsInterfaceLinkLocalMulticast returns true if ip is
+// an interface-local multicast address.
+func (ip IP) IsInterfaceLocalMulticast() bool {
+ return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01
+}
+
+// IsLinkLocalMulticast returns true if ip is a link-local
+// multicast address.
+func (ip IP) IsLinkLocalMulticast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 {
+ return true
+ }
+ return ip[0] == 0xff && ip[1]&0x0f == 0x02
+}
+
+// IsLinkLocalUnicast returns true if ip is a link-local
+// unicast address.
+func (ip IP) IsLinkLocalUnicast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 169 && ip4[1] == 254 {
+ return true
+ }
+ return ip[0] == 0xfe && ip[1]&0xc0 == 0x80
+}
+
+// IsGlobalUnicast returns true if ip is a global unicast
+// address.
+func (ip IP) IsGlobalUnicast() bool {
+ return !ip.IsUnspecified() &&
+ !ip.IsLoopback() &&
+ !ip.IsMulticast() &&
+ !ip.IsLinkLocalUnicast()
+}
+
// Is p all zeros?
func isZeros(p IP) bool {
for i := 0; i < len(p); i++ {
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
index 2008953ef38..b189b10c4fd 100644
--- a/libgo/go/net/ip_test.go
+++ b/libgo/go/net/ip_test.go
@@ -9,6 +9,7 @@ import (
"reflect"
"testing"
"os"
+ "runtime"
)
func isEqual(a, b []byte) bool {
@@ -31,11 +32,7 @@ var parseiptests = []struct {
{"abc", nil},
{"123:", 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,
- },
- },
+ {"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)},
}
@@ -52,29 +49,21 @@ var ipstringtests = []struct {
out string
}{
// 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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
"2001:db8::a:b:c:d"},
}
@@ -143,3 +132,84 @@ func TestJoinHostPort(t *testing.T) {
}
}
}
+
+var ipaftests = []struct {
+ in IP
+ af4 bool
+ af6 bool
+}{
+ {IPv4bcast, true, false},
+ {IPv4allsys, true, false},
+ {IPv4allrouter, true, false},
+ {IPv4zero, true, false},
+ {IPv4(224, 0, 0, 1), true, false},
+ {IPv4(127, 0, 0, 1), true, false},
+ {IPv4(240, 0, 0, 1), true, false},
+ {IPv6unspecified, false, true},
+ {IPv6loopback, false, true},
+ {IPv6interfacelocalallnodes, false, true},
+ {IPv6linklocalallnodes, false, true},
+ {IPv6linklocalallrouters, false, true},
+ {ParseIP("ff05::a:b:c:d"), false, true},
+ {ParseIP("fe80::1:2:3:4"), false, true},
+ {ParseIP("2001:db8::123:12:1"), false, true},
+}
+
+func TestIPAddrFamily(t *testing.T) {
+ for _, tt := range ipaftests {
+ if af := tt.in.To4() != nil; af != tt.af4 {
+ t.Errorf("verifying IPv4 address family for %#q = %v, want %v", tt.in, af, tt.af4)
+ }
+ if af := len(tt.in) == IPv6len && tt.in.To4() == nil; af != tt.af6 {
+ t.Errorf("verifying IPv6 address family for %#q = %v, want %v", tt.in, af, tt.af6)
+ }
+ }
+}
+
+var ipscopetests = []struct {
+ scope func(IP) bool
+ in IP
+ ok bool
+}{
+ {IP.IsUnspecified, IPv4zero, true},
+ {IP.IsUnspecified, IPv4(127, 0, 0, 1), false},
+ {IP.IsUnspecified, IPv6unspecified, true},
+ {IP.IsUnspecified, IPv6interfacelocalallnodes, false},
+ {IP.IsLoopback, IPv4(127, 0, 0, 1), true},
+ {IP.IsLoopback, IPv4(127, 255, 255, 254), true},
+ {IP.IsLoopback, IPv4(128, 1, 2, 3), false},
+ {IP.IsLoopback, IPv6loopback, true},
+ {IP.IsLoopback, IPv6linklocalallrouters, false},
+ {IP.IsMulticast, IPv4(224, 0, 0, 0), true},
+ {IP.IsMulticast, IPv4(239, 0, 0, 0), true},
+ {IP.IsMulticast, IPv4(240, 0, 0, 0), false},
+ {IP.IsMulticast, IPv6linklocalallnodes, true},
+ {IP.IsMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
+ {IP.IsMulticast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsLinkLocalMulticast, IPv4(224, 0, 0, 0), true},
+ {IP.IsLinkLocalMulticast, IPv4(239, 0, 0, 0), false},
+ {IP.IsLinkLocalMulticast, IPv6linklocalallrouters, true},
+ {IP.IsLinkLocalMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsLinkLocalUnicast, IPv4(169, 254, 0, 0), true},
+ {IP.IsLinkLocalUnicast, IPv4(169, 255, 0, 0), false},
+ {IP.IsLinkLocalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
+ {IP.IsLinkLocalUnicast, IP{0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsGlobalUnicast, IPv4(240, 0, 0, 0), true},
+ {IP.IsGlobalUnicast, IPv4(232, 0, 0, 0), false},
+ {IP.IsGlobalUnicast, IPv4(169, 254, 0, 0), false},
+ {IP.IsGlobalUnicast, IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, true},
+ {IP.IsGlobalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsGlobalUnicast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+}
+
+func name(f interface{}) string {
+ return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
+}
+
+func TestIPAddrScope(t *testing.T) {
+ for _, tt := range ipscopetests {
+ if ok := tt.scope(tt.in); ok != tt.ok {
+ t.Errorf("%s(%#q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok)
+ }
+ }
+}
diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go
index 0c0b675f875..6894ce656dd 100644
--- a/libgo/go/net/ipraw_test.go
+++ b/libgo/go/net/ipraw_test.go
@@ -2,7 +2,6 @@
// 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
@@ -75,15 +74,15 @@ func TestICMP(t *testing.T) {
err os.Error
)
if *srchost != "" {
- laddr, err = ResolveIPAddr(*srchost)
+ laddr, err = ResolveIPAddr("ip4", *srchost)
if err != nil {
- t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *srchost, laddr, err)
+ t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *srchost, laddr, err)
}
}
- raddr, err := ResolveIPAddr(*dsthost)
+ raddr, err := ResolveIPAddr("ip4", *dsthost)
if err != nil {
- t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *dsthost, raddr, err)
+ t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *dsthost, raddr, err)
}
c, err := ListenIP("ip4:icmp", laddr)
diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go
index 5be6fe4e0b9..662b9f57bd3 100644
--- a/libgo/go/net/iprawsock.go
+++ b/libgo/go/net/iprawsock.go
@@ -8,22 +8,8 @@ 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
@@ -39,320 +25,45 @@ func (a *IPAddr) String() string {
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
+// names to numeric addresses on the network net, which must be
+// "ip", "ip4" or "ip6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]".
-func ResolveIPAddr(addr string) (*IPAddr, os.Error) {
- ip, err := hostToIP(addr)
+func ResolveIPAddr(net, addr string) (*IPAddr, os.Error) {
+ ip, err := hostToIP(net, 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) {
+func hostToIP(net, host string) (ip IP, err os.Error) {
var addr IP
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
+ filter := anyaddr
+ if net != "" && net[len(net)-1] == '4' {
+ filter = ipv4only
+ }
+ if net != "" && net[len(net)-1] == '6' {
+ filter = ipv6only
+ }
// Not an IP address. Try as a DNS name.
addrs, err1 := LookupHost(host)
if err1 != nil {
err = err1
goto Error
}
- addr = firstSupportedAddr(anyaddr, addrs)
+ addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
- err = &AddrError{"LookupHost returned invalid address", addrs[0]}
+ err = &AddrError{"LookupHost returned no suitable 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 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 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/iprawsock_plan9.go b/libgo/go/net/iprawsock_plan9.go
new file mode 100644
index 00000000000..808e17974f8
--- /dev/null
+++ b/libgo/go/net/iprawsock_plan9.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.
+
+// (Raw) IP sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// IPConn is the implementation of the Conn and PacketConn
+// interfaces for IP network connections.
+type IPConn bool
+
+// 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) {
+ return 0, os.EPLAN9
+}
+
+// Write implements the net.Conn Write method.
+func (c *IPConn) Write(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Close closes the IP connection.
+func (c *IPConn) Close() os.Error {
+ return os.EPLAN9
+}
+
+// LocalAddr returns the local network address.
+func (c *IPConn) LocalAddr() Addr {
+ return nil
+}
+
+// RemoteAddr returns the remote network address, a *IPAddr.
+func (c *IPConn) RemoteAddr() Addr {
+ return nil
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *IPConn) SetTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// IP-specific methods.
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// 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) {
+ return 0, os.EPLAN9
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+func splitNetProto(netProto string) (net string, proto int, err os.Error) {
+ err = os.EPLAN9
+ 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) {
+ return nil, os.EPLAN9
+}
+
+// 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) {
+ return nil, os.EPLAN9
+}
diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go
new file mode 100644
index 00000000000..4e115180061
--- /dev/null
+++ b/libgo/go/net/iprawsock_posix.go
@@ -0,0 +1,305 @@
+// 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
+}
+
+func (a *IPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != 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
+}
+
+// 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)
+}
+
+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 splitNetProto(netProto string) (net string, proto int, err os.Error) {
+ onceReadProtocols.Do(readProtocols)
+ i := last(netProto, ':')
+ if i < 0 { // no colon
+ return "", 0, os.NewError("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 := splitNetProto(netProto)
+ if err != nil {
+ return
+ }
+ switch 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 := splitNetProto(netProto)
+ if err != nil {
+ return
+ }
+ switch 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
index e8bcac64603..4e2a5622b36 100644
--- a/libgo/go/net/ipsock.go
+++ b/libgo/go/net/ipsock.go
@@ -8,33 +8,27 @@ 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 {
- s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
- if err != 0 {
- return false
- }
- defer closesocket(s)
+var supportsIPv6, supportsIPv4map = probeIPv6Stack()
- la := &TCPAddr{IP: IPv4(127, 0, 0, 1)}
- sa, oserr := la.toAddr().sockaddr(syscall.AF_INET6)
- if oserr != nil {
- return false
+func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
+ if filter == anyaddr {
+ // We'll take any IP address, but since the dialing code
+ // does not yet try multiple addresses, prefer to use
+ // an IPv4 address if possible. This is especially relevant
+ // if localhost resolves to [ipv6-localhost, ipv4-localhost].
+ // Too much code assumes localhost == ipv4-localhost.
+ addr = firstSupportedAddr(ipv4only, addrs)
+ if addr == nil {
+ addr = firstSupportedAddr(anyaddr, addrs)
+ }
+ } else {
+ addr = firstSupportedAddr(filter, addrs)
}
-
- return syscall.Bind(s, sa) == 0
+ return
}
-var preferIPv4 = !kernelSupportsIPv6()
-
func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
for _, s := range addrs {
if addr := filter(ParseIP(s)); addr != nil {
@@ -44,98 +38,25 @@ func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
return nil
}
-func anyaddr(x IP) IP { return x }
+func anyaddr(x IP) IP {
+ if x4 := x.To4(); x4 != nil {
+ return x4
+ }
+ if supportsIPv6 {
+ return x
+ }
+ return nil
+}
+
func ipv4only(x IP) IP { return x.To4() }
func ipv6only(x IP) IP {
// Only return addresses that we can use
// with the kernel's IPv6 addressing modes.
- // If preferIPv4 is set, it means the IPv6 stack
- // cannot take IPv4 addresses directly (we prefer
- // to use the IPv4 stack) so reject IPv4 addresses.
- if x.To4() != nil && preferIPv4 {
- return nil
- }
- return x
-}
-
-// 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
- }
+ if len(x) == IPv6len && x.To4() == nil && supportsIPv6 {
+ return x
}
-
- 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
+ return nil
}
type InvalidAddrError string
@@ -144,44 +65,6 @@ 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")
-}
-
// SplitHostPort splits a network address of the form
// "host:port" or "[host]:port" into host and port.
// The latter form must be used when host contains a colon.
@@ -220,20 +103,25 @@ func JoinHostPort(host, port string) string {
// Convert "host:port" into IP address and port.
func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
+ var (
+ addr IP
+ p, i int
+ ok bool
+ )
host, port, err := SplitHostPort(hostport)
if err != nil {
goto Error
}
- var addr IP
if host != "" {
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
filter := anyaddr
- if len(net) >= 4 && net[3] == '4' {
+ if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
- } else if len(net) >= 4 && net[3] == '6' {
+ }
+ if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
// Not an IP address. Try as a DNS name.
@@ -242,28 +130,16 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
err = err1
goto Error
}
- if filter == anyaddr {
- // We'll take any IP address, but since the dialing code
- // does not yet try multiple addresses, prefer to use
- // an IPv4 address if possible. This is especially relevant
- // if localhost resolves to [ipv6-localhost, ipv4-localhost].
- // Too much code assumes localhost == ipv4-localhost.
- addr = firstSupportedAddr(ipv4only, addrs)
- if addr == nil {
- addr = firstSupportedAddr(anyaddr, addrs)
- }
- } else {
- addr = firstSupportedAddr(filter, addrs)
- }
+ addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
- err = &AddrError{"LookupHost returned invalid address", addrs[0]}
+ err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
goto Error
}
}
}
- p, i, ok := dtoi(port, 0)
+ p, i, ok = dtoi(port, 0)
if !ok || i != len(port) {
p, err = LookupPort(net, port)
if err != nil {
diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go
new file mode 100644
index 00000000000..9e5da6d38a7
--- /dev/null
+++ b/libgo/go/net/ipsock_plan9.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.
+
+// IP sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// probeIPv6Stack returns two boolean values. If the first boolean value is
+// true, kernel supports basic IPv6 functionality. If the second
+// boolean value is true, kernel supports IPv6 IPv4-mapping.
+func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
+ return false, false
+}
+
+// parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
+func parsePlan9Addr(s string) (ip IP, iport int, err os.Error) {
+ var (
+ addr IP
+ p, i int
+ ok bool
+ )
+ addr = IPv4zero // address contains port only
+ i = byteIndex(s, '!')
+ if i >= 0 {
+ addr = ParseIP(s[:i])
+ if addr == nil {
+ err = os.NewError("net: parsing IP failed")
+ goto Error
+ }
+ }
+ p, _, ok = dtoi(s[i+1:], 0)
+ if !ok {
+ err = os.NewError("net: parsing port failed")
+ goto Error
+ }
+ if p < 0 || p > 0xFFFF {
+ err = &AddrError{"invalid port", string(p)}
+ goto Error
+ }
+ return addr, p, nil
+
+Error:
+ return nil, 0, err
+}
+
+func readPlan9Addr(proto, filename string) (addr Addr, err os.Error) {
+ var buf [128]byte
+
+ f, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ ip, port, err := parsePlan9Addr(string(buf[:n]))
+ if err != nil {
+ return
+ }
+ switch proto {
+ case "tcp":
+ addr = &TCPAddr{ip, port}
+ case "udp":
+ addr = &UDPAddr{ip, port}
+ default:
+ return nil, os.NewError("unknown protocol " + proto)
+ }
+ return addr, nil
+}
+
+type plan9Conn struct {
+ proto, name, dir string
+ ctl, data *os.File
+ laddr, raddr Addr
+}
+
+func newPlan9Conn(proto, name string, ctl *os.File, laddr, raddr Addr) *plan9Conn {
+ return &plan9Conn{proto, name, "/net/" + proto + "/" + name, ctl, nil, laddr, raddr}
+}
+
+func (c *plan9Conn) ok() bool { return c != nil && c.ctl != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *plan9Conn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ n, err = c.data.Read(b)
+ if c.proto == "udp" && err == os.EOF {
+ n = 0
+ err = nil
+ }
+ return
+}
+
+// Write implements the net.Conn Write method.
+func (c *plan9Conn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ return c.data.Write(b)
+}
+
+// Close closes the connection.
+func (c *plan9Conn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.ctl.Close()
+ if err != nil {
+ return err
+ }
+ if c.data != nil {
+ err = c.data.Close()
+ }
+ c.ctl = nil
+ c.data = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *plan9Conn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.laddr
+}
+
+// RemoteAddr returns the remote network address.
+func (c *plan9Conn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *plan9Conn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *plan9Conn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *plan9Conn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err os.Error) {
+ var (
+ ip IP
+ port int
+ )
+ switch a := addr.(type) {
+ case *TCPAddr:
+ proto = "tcp"
+ ip = a.IP
+ port = a.Port
+ case *UDPAddr:
+ proto = "udp"
+ ip = a.IP
+ port = a.Port
+ default:
+ err = UnknownNetworkError(net)
+ return
+ }
+
+ clone, dest, err := queryCS1(proto, ip, port)
+ if err != nil {
+ return
+ }
+ f, err := os.OpenFile(clone, os.O_RDWR, 0)
+ if err != nil {
+ return
+ }
+ var buf [16]byte
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ return f, dest, proto, string(buf[:n]), nil
+}
+
+func dialPlan9(net string, laddr, raddr Addr) (c *plan9Conn, err os.Error) {
+ f, dest, proto, name, err := startPlan9(net, raddr)
+ if err != nil {
+ return
+ }
+ _, err = f.WriteString("connect " + dest)
+ if err != nil {
+ return
+ }
+ laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ if err != nil {
+ return
+ }
+ raddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/remote")
+ if err != nil {
+ return
+ }
+ return newPlan9Conn(proto, name, f, laddr, raddr), nil
+}
+
+type plan9Listener struct {
+ proto, name, dir string
+ ctl *os.File
+ laddr Addr
+}
+
+func listenPlan9(net string, laddr Addr) (l *plan9Listener, err os.Error) {
+ f, dest, proto, name, err := startPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ _, err = f.WriteString("announce " + dest)
+ if err != nil {
+ return
+ }
+ laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ if err != nil {
+ return
+ }
+ l = new(plan9Listener)
+ l.proto = proto
+ l.name = name
+ l.dir = "/net/" + proto + "/" + name
+ l.ctl = f
+ l.laddr = laddr
+ return l, nil
+}
+
+func (l *plan9Listener) plan9Conn() *plan9Conn {
+ return newPlan9Conn(l.proto, l.name, l.ctl, l.laddr, nil)
+}
+
+func (l *plan9Listener) acceptPlan9() (c *plan9Conn, err os.Error) {
+ f, err := os.Open(l.dir + "/listen")
+ if err != nil {
+ return
+ }
+ var buf [16]byte
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ name := string(buf[:n])
+ laddr, err := readPlan9Addr(l.proto, l.dir+"/local")
+ if err != nil {
+ return
+ }
+ raddr, err := readPlan9Addr(l.proto, l.dir+"/remote")
+ if err != nil {
+ return
+ }
+ return newPlan9Conn(l.proto, name, f, laddr, raddr), nil
+}
+
+func (l *plan9Listener) Accept() (c Conn, err os.Error) {
+ c1, err := l.acceptPlan9()
+ if err != nil {
+ return
+ }
+ return c1, nil
+}
+
+func (l *plan9Listener) Close() os.Error {
+ if l == nil || l.ctl == nil {
+ return os.EINVAL
+ }
+ return l.ctl.Close()
+}
+
+func (l *plan9Listener) Addr() Addr { return l.laddr }
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
new file mode 100644
index 00000000000..0c522fb7fbe
--- /dev/null
+++ b/libgo/go/net/ipsock_posix.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 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.
+//
+// probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4-
+// mapping capability which is controlled by IPV6_V6ONLY socket
+// option and/or kernel state "net.inet6.ip6.v6only".
+// It returns two boolean values. If the first boolean value is
+// true, kernel supports basic IPv6 functionality. If the second
+// boolean value is true, kernel supports IPv6 IPv4-mapping.
+func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
+ var probes = []struct {
+ la TCPAddr
+ ok bool
+ }{
+ // IPv6 communication capability
+ {TCPAddr{IP: ParseIP("::1")}, false},
+ // IPv6 IPv4-mapped address communication capability
+ {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
+ }
+
+ for i := range probes {
+ s, errno := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+ if errno != 0 {
+ continue
+ }
+ defer closesocket(s)
+ sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
+ if err != nil {
+ continue
+ }
+ errno = syscall.Bind(s, sa)
+ if errno != 0 {
+ continue
+ }
+ probes[i].ok = true
+ }
+
+ return probes[0].ok, probes[1].ok
+}
+
+// favoriteAddrFamily returns the appropriate address family to
+// the given net, raddr, laddr and mode. At first it figures
+// address family out from the net. If mode indicates "listen"
+// and laddr.(type).IP is nil, it assumes that the user wants to
+// make a passive connection with wildcard address family, both
+// INET and INET6, and wildcard address. Otherwise guess: if the
+// addresses are IPv4 then returns INET, or else returns INET6.
+func favoriteAddrFamily(net string, raddr, laddr sockaddr, mode string) int {
+ switch net[len(net)-1] {
+ case '4':
+ return syscall.AF_INET
+ case '6':
+ return syscall.AF_INET6
+ }
+
+ if mode == "listen" {
+ switch a := laddr.(type) {
+ case *TCPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ case *UDPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ case *IPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ }
+ }
+
+ if (laddr == nil || laddr.family() == syscall.AF_INET) &&
+ (raddr == nil || raddr.family() == syscall.AF_INET) {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+// TODO(rsc): if syscall.OS == "linux", we're supposed 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) {
+ var oserr os.Error
+ var la, ra syscall.Sockaddr
+ family := favoriteAddrFamily(net, raddr, laddr, mode)
+ 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 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 = IPv6zero
+ }
+ // 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 ip.Equal(IPv4zero) {
+ ip = IPv6zero
+ }
+ 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")
+}
diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go
deleted file mode 100644
index eeb22a8ae3d..00000000000
--- a/libgo/go/net/lookup.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package net
-
-import (
- "os"
-)
-
-// LookupHost looks up the given host using the local resolver.
-// It returns an array of that host's addresses.
-func LookupHost(host string) (addrs []string, err os.Error) {
- addrs, err, ok := cgoLookupHost(host)
- if !ok {
- addrs, err = goLookupHost(host)
- }
- return
-}
-
-// LookupIP looks up host using the local resolver.
-// It returns an array of that host's IPv4 and IPv6 addresses.
-func LookupIP(host string) (addrs []IP, err os.Error) {
- addrs, err, ok := cgoLookupIP(host)
- if !ok {
- addrs, err = goLookupIP(host)
- }
- return
-}
-
-// LookupPort looks up the port for the given network and service.
-func LookupPort(network, service string) (port int, err os.Error) {
- port, err, ok := cgoLookupPort(network, service)
- if !ok {
- port, err = goLookupPort(network, service)
- }
- return
-}
-
-// LookupCNAME returns the canonical DNS host for the given name.
-// Callers that do not care about the canonical name can call
-// LookupHost or LookupIP directly; both take care of resolving
-// the canonical name as part of the lookup.
-func LookupCNAME(name string) (cname string, err os.Error) {
- cname, err, ok := cgoLookupCNAME(name)
- if !ok {
- cname, err = goLookupCNAME(name)
- }
- return
-}
diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go
new file mode 100644
index 00000000000..37d6b8e315a
--- /dev/null
+++ b/libgo/go/net/lookup_plan9.go
@@ -0,0 +1,226 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+)
+
+func query(filename, query string, bufSize int) (res []string, err os.Error) {
+ file, err := os.OpenFile(filename, os.O_RDWR, 0)
+ if err != nil {
+ return
+ }
+ defer file.Close()
+
+ _, err = file.WriteString(query)
+ if err != nil {
+ return
+ }
+ _, err = file.Seek(0, 0)
+ if err != nil {
+ return
+ }
+ buf := make([]byte, bufSize)
+ for {
+ n, _ := file.Read(buf)
+ if n <= 0 {
+ break
+ }
+ res = append(res, string(buf[:n]))
+ }
+ return
+}
+
+func queryCS(net, host, service string) (res []string, err os.Error) {
+ switch net {
+ case "tcp4", "tcp6":
+ net = "tcp"
+ case "udp4", "udp6":
+ net = "udp"
+ }
+ if host == "" {
+ host = "*"
+ }
+ return query("/net/cs", net+"!"+host+"!"+service, 128)
+}
+
+func queryCS1(net string, ip IP, port int) (clone, dest string, err os.Error) {
+ ips := "*"
+ if !ip.IsUnspecified() {
+ ips = ip.String()
+ }
+ lines, err := queryCS(net, ips, itoa(port))
+ if err != nil {
+ return
+ }
+ f := getFields(lines[0])
+ if len(f) < 2 {
+ return "", "", os.NewError("net: bad response from ndb/cs")
+ }
+ clone, dest = f[0], f[1]
+ return
+}
+
+func queryDNS(addr string, typ string) (res []string, err os.Error) {
+ return query("/net/dns", addr+" "+typ, 1024)
+}
+
+// LookupHost looks up the given host using the local resolver.
+// It returns an array of that host's addresses.
+func LookupHost(host string) (addrs []string, err os.Error) {
+ // Use /net/cs insead of /net/dns because cs knows about
+ // host names in local network (e.g. from /lib/ndb/local)
+ lines, err := queryCS("tcp", host, "1")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ addr := f[1]
+ if i := byteIndex(addr, '!'); i >= 0 {
+ addr = addr[:i] // remove port
+ }
+ if ParseIP(addr) == nil {
+ continue
+ }
+ addrs = append(addrs, addr)
+ }
+ return
+}
+
+// LookupIP looks up host using the local resolver.
+// It returns an array of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) (ips []IP, err os.Error) {
+ addrs, err := LookupHost(host)
+ if err != nil {
+ return
+ }
+ for _, addr := range addrs {
+ if ip := ParseIP(addr); ip != nil {
+ ips = append(ips, ip)
+ }
+ }
+ return
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+ lines, err := queryCS(network, "127.0.0.1", service)
+ if err != nil {
+ return
+ }
+ unknownPortError := &AddrError{"unknown port", network + "/" + service}
+ if len(lines) == 0 {
+ return 0, unknownPortError
+ }
+ f := getFields(lines[0])
+ if len(f) < 2 {
+ return 0, unknownPortError
+ }
+ s := f[1]
+ if i := byteIndex(s, '!'); i >= 0 {
+ s = s[i+1:] // remove address
+ }
+ if n, _, ok := dtoi(s, 0); ok {
+ return n, nil
+ }
+ return 0, unknownPortError
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func LookupCNAME(name string) (cname string, err os.Error) {
+ lines, err := queryDNS(name, "cname")
+ if err != nil {
+ return
+ }
+ if len(lines) > 0 {
+ if f := getFields(lines[0]); len(f) >= 3 {
+ return f[2] + ".", nil
+ }
+ }
+ return "", os.NewError("net: bad response from ndb/dns")
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network(). The returned records are sorted by priority
+// and randomized by weight within a priority.
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
+ lines, err := queryDNS(target, "srv")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 6 {
+ continue
+ }
+ port, _, portOk := dtoi(f[2], 0)
+ priority, _, priorityOk := dtoi(f[3], 0)
+ weight, _, weightOk := dtoi(f[4], 0)
+ if !(portOk && priorityOk && weightOk) {
+ continue
+ }
+ addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)})
+ cname = f[0]
+ }
+ byPriorityWeight(addrs).sort()
+ return
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ lines, err := queryDNS(name, "mx")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 4 {
+ continue
+ }
+ if pref, _, ok := dtoi(f[2], 0); ok {
+ mx = append(mx, &MX{f[3], uint16(pref)})
+ }
+ }
+ byPref(mx).sort()
+ return
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func LookupAddr(addr string) (name []string, err os.Error) {
+ arpa, err := reverseaddr(addr)
+ if err != nil {
+ return
+ }
+ lines, err := queryDNS(arpa, "ptr")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 3 {
+ continue
+ }
+ name = append(name, f[2])
+ }
+ return
+}
diff --git a/libgo/go/net/srv_test.go b/libgo/go/net/lookup_test.go
index f1c7a0ab498..995ab03d090 100644
--- a/libgo/go/net/srv_test.go
+++ b/libgo/go/net/lookup_test.go
@@ -27,3 +27,31 @@ func TestGoogleSRV(t *testing.T) {
t.Errorf("no results")
}
}
+
+func TestGmailMX(t *testing.T) {
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ mx, err := LookupMX("gmail.com")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(mx) == 0 {
+ t.Errorf("no results")
+ }
+}
+
+func TestGoogleDNSAddr(t *testing.T) {
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ names, err := LookupAddr("8.8.8.8")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(names) == 0 {
+ t.Errorf("no results")
+ }
+}
diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go
new file mode 100644
index 00000000000..8f5e66212b3
--- /dev/null
+++ b/libgo/go/net/lookup_unix.go
@@ -0,0 +1,111 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+)
+
+// LookupHost looks up the given host using the local resolver.
+// It returns an array of that host's addresses.
+func LookupHost(host string) (addrs []string, err os.Error) {
+ addrs, err, ok := cgoLookupHost(host)
+ if !ok {
+ addrs, err = goLookupHost(host)
+ }
+ return
+}
+
+// LookupIP looks up host using the local resolver.
+// It returns an array of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) (addrs []IP, err os.Error) {
+ addrs, err, ok := cgoLookupIP(host)
+ if !ok {
+ addrs, err = goLookupIP(host)
+ }
+ return
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+ port, err, ok := cgoLookupPort(network, service)
+ if !ok {
+ port, err = goLookupPort(network, service)
+ }
+ return
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func LookupCNAME(name string) (cname string, err os.Error) {
+ cname, err, ok := cgoLookupCNAME(name)
+ if !ok {
+ cname, err = goLookupCNAME(name)
+ }
+ return
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network(). The returned records are sorted by priority
+// and randomized by weight within a priority.
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
+ var records []dnsRR
+ cname, records, err = lookup(target, dnsTypeSRV)
+ if err != nil {
+ return
+ }
+ addrs = make([]*SRV, len(records))
+ for i, rr := range records {
+ r := rr.(*dnsRR_SRV)
+ addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+ }
+ byPriorityWeight(addrs).sort()
+ return
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ _, rr, err := lookup(name, dnsTypeMX)
+ if err != nil {
+ return
+ }
+ mx = make([]*MX, len(rr))
+ for i := range rr {
+ r := rr[i].(*dnsRR_MX)
+ mx[i] = &MX{r.Mx, r.Pref}
+ }
+ byPref(mx).sort()
+ return
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func LookupAddr(addr string) (name []string, err os.Error) {
+ name = lookupStaticAddr(addr)
+ if len(name) > 0 {
+ return
+ }
+ var arpa string
+ arpa, err = reverseaddr(addr)
+ if err != nil {
+ return
+ }
+ var records []dnsRR
+ _, records, err = lookup(arpa, dnsTypePTR)
+ if err != nil {
+ return
+ }
+ name = make([]string, len(records))
+ for i := range records {
+ r := records[i].(*dnsRR_PTR)
+ name[i] = r.Ptr
+ }
+ return
+}
diff --git a/libgo/go/net/resolv_windows.go b/libgo/go/net/lookup_windows.go
index f7c3f51bef1..fa3ad7c7f42 100644
--- a/libgo/go/net/resolv_windows.go
+++ b/libgo/go/net/lookup_windows.go
@@ -14,8 +14,8 @@ import (
var hostentLock sync.Mutex
var serventLock sync.Mutex
-func goLookupHost(name string) (addrs []string, err os.Error) {
- ips, err := goLookupIP(name)
+func LookupHost(name string) (addrs []string, err os.Error) {
+ ips, err := LookupIP(name)
if err != nil {
return
}
@@ -26,7 +26,7 @@ func goLookupHost(name string) (addrs []string, err os.Error) {
return
}
-func goLookupIP(name string) (addrs []IP, err os.Error) {
+func LookupIP(name string) (addrs []IP, err os.Error) {
hostentLock.Lock()
defer hostentLock.Unlock()
h, e := syscall.GetHostByName(name)
@@ -47,7 +47,23 @@ func goLookupIP(name string) (addrs []IP, err os.Error) {
return addrs, nil
}
-func goLookupCNAME(name string) (cname string, err os.Error) {
+func LookupPort(network, service string) (port int, err os.Error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+ serventLock.Lock()
+ defer serventLock.Unlock()
+ s, e := syscall.GetServByName(service, network)
+ if e != 0 {
+ return 0, os.NewSyscallError("GetServByName", e)
+ }
+ return int(syscall.Ntohs(s.Port)), nil
+}
+
+func LookupCNAME(name string) (cname string, err os.Error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
if int(e) != 0 {
@@ -61,13 +77,6 @@ func goLookupCNAME(name string) (cname string, err os.Error) {
return
}
-type SRV struct {
- Target string
- Port uint16
- Priority uint16
- Weight uint16
-}
-
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
var r *syscall.DNSRecord
target := "_" + service + "._" + proto + "." + name
@@ -76,66 +85,46 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return "", nil, os.NewSyscallError("LookupSRV", int(e))
}
defer syscall.DnsRecordListFree(r, 1)
- addrs = make([]*SRV, 100)
- i := 0
+ addrs = make([]*SRV, 0, 10)
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 = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
}
- addrs = addrs[0:i]
+ byPriorityWeight(addrs).sort()
return name, addrs, nil
}
-func goLookupPort(network, service string) (port int, err os.Error) {
- switch network {
- case "tcp4", "tcp6":
- network = "tcp"
- case "udp4", "udp6":
- network = "udp"
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ var r *syscall.DNSRecord
+ e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return nil, os.NewSyscallError("LookupMX", int(e))
}
- serventLock.Lock()
- defer serventLock.Unlock()
- s, e := syscall.GetServByName(service, network)
- if e != 0 {
- return 0, os.NewSyscallError("GetServByName", e)
+ defer syscall.DnsRecordListFree(r, 1)
+ mx = make([]*MX, 0, 10)
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_MX; p = p.Next {
+ v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
+ mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
}
- return int(syscall.Ntohs(s.Port)), nil
-}
-
-// TODO(brainman): Following code is only to get tests running.
-
-func isDomainName(s string) bool {
- panic("unimplemented")
+ byPref(mx).sort()
+ return mx, nil
}
-func reverseaddr(addr string) (arpa string, err os.Error) {
- panic("unimplemented")
-}
-
-func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- panic("unimplemented")
-}
-
-// 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>"
+func LookupAddr(addr string) (name []string, err os.Error) {
+ arpa, err := reverseaddr(addr)
+ if err != nil {
+ return nil, err
}
- s := "lookup " + e.Name
- if e.Server != "" {
- s += " on " + e.Server
+ var r *syscall.DNSRecord
+ e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return nil, os.NewSyscallError("LookupAddr", int(e))
}
- s += ": " + e.Error
- return s
+ defer syscall.DnsRecordListFree(r, 1)
+ name = make([]string, 0, 10)
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_PTR; p = p.Next {
+ v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
+ name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
+ }
+ return name, nil
}
-
-func (e *DNSError) Timeout() bool { return e.IsTimeout }
-func (e *DNSError) Temporary() bool { return e.IsTimeout }
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index 51db1073954..5c84d34348a 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -115,7 +115,7 @@ type Listener interface {
Addr() Addr
}
-var errMissingAddress = os.ErrorString("missing address")
+var errMissingAddress = os.NewError("missing address")
type OpError struct {
Op string
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
index da7928351ce..dc0d49d23ac 100644
--- a/libgo/go/net/net_test.go
+++ b/libgo/go/net/net_test.go
@@ -7,7 +7,6 @@ package net
import (
"flag"
"regexp"
- "runtime"
"testing"
)
@@ -103,9 +102,6 @@ var revAddrTests = []struct {
}
func TestReverseAddress(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
for i, tt := range revAddrTests {
a, e := reverseaddr(tt.Addr)
if len(tt.ErrPrefix) > 0 && e == nil {
diff --git a/libgo/go/net/newpollserver.go b/libgo/go/net/newpollserver.go
index fff54dba71f..427208701b3 100644
--- a/libgo/go/net/newpollserver.go
+++ b/libgo/go/net/newpollserver.go
@@ -18,12 +18,7 @@ func newPollServer() (s *pollServer, err os.Error) {
}
var e int
if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
- Errno:
- err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
- Error:
- s.pr.Close()
- s.pw.Close()
- return nil, err
+ goto Errno
}
if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
goto Errno
@@ -38,4 +33,11 @@ func newPollServer() (s *pollServer, err os.Error) {
s.pending = make(map[int]*netFD)
go s.Run()
return s, nil
+
+Errno:
+ err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+Error:
+ s.pr.Close()
+ s.pw.Close()
+ return nil, err
}
diff --git a/libgo/go/net/parse_test.go b/libgo/go/net/parse_test.go
index 226f354d300..8d51eba18c3 100644
--- a/libgo/go/net/parse_test.go
+++ b/libgo/go/net/parse_test.go
@@ -12,8 +12,8 @@ import (
)
func TestReadLine(t *testing.T) {
- // /etc/services file does not exist on windows.
- if runtime.GOOS == "windows" {
+ // /etc/services file does not exist on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
filename := "/etc/services" // a nice big file
diff --git a/libgo/go/net/sendfile_linux.go b/libgo/go/net/sendfile_linux.go
new file mode 100644
index 00000000000..6a5a06c8c54
--- /dev/null
+++ b/libgo/go/net/sendfile_linux.go
@@ -0,0 +1,84 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// sendFile copies the contents of r to c using the sendfile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) {
+ var remain int64 = 1 << 62 // by default, copy until EOF
+
+ lr, ok := r.(*io.LimitedReader)
+ if ok {
+ remain, r = lr.N, lr.R
+ if remain <= 0 {
+ return 0, nil, true
+ }
+ }
+ f, ok := r.(*os.File)
+ if !ok {
+ return 0, nil, false
+ }
+
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.incref()
+ defer c.decref()
+ if c.wdeadline_delta > 0 {
+ // This is a little odd that we're setting the timeout
+ // for the entire file but Write has the same issue
+ // (if one slurps the whole file into memory and
+ // do one large Write). At least they're consistent.
+ c.wdeadline = pollserver.Now() + c.wdeadline_delta
+ } else {
+ c.wdeadline = 0
+ }
+
+ dst := c.sysfd
+ src := f.Fd()
+ for remain > 0 {
+ n := maxSendfileSize
+ if int64(n) > remain {
+ n = int(remain)
+ }
+ n, errno := syscall.Sendfile(dst, src, nil, n)
+ if n > 0 {
+ written += int64(n)
+ remain -= int64(n)
+ }
+ if n == 0 && errno == 0 {
+ break
+ }
+ if errno == syscall.EAGAIN && c.wdeadline >= 0 {
+ pollserver.WaitWrite(c)
+ continue
+ }
+ if errno != 0 {
+ // This includes syscall.ENOSYS (no kernel
+ // support) and syscall.EINVAL (fd types which
+ // don't implement sendfile together)
+ err = &OpError{"sendfile", c.net, c.raddr, os.Errno(errno)}
+ break
+ }
+ }
+ if lr != nil {
+ lr.N = remain
+ }
+ return written, err, written > 0
+}
diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go
new file mode 100644
index 00000000000..43e8104e94c
--- /dev/null
+++ b/libgo/go/net/sendfile_stub.go
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "io"
+ "os"
+)
+
+func sendFile(c *netFD, r io.Reader) (n int64, err os.Error, handled bool) {
+ return 0, nil, false
+}
diff --git a/libgo/go/net/sendfile_windows.go b/libgo/go/net/sendfile_windows.go
new file mode 100644
index 00000000000..3772eee2490
--- /dev/null
+++ b/libgo/go/net/sendfile_windows.go
@@ -0,0 +1,68 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+type sendfileOp struct {
+ anOp
+ src syscall.Handle // source
+ n uint32
+}
+
+func (o *sendfileOp) Submit() (errno int) {
+ return syscall.TransmitFile(o.fd.sysfd, o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
+}
+
+func (o *sendfileOp) Name() string {
+ return "TransmitFile"
+}
+
+// sendFile copies the contents of r to c using the TransmitFile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+//
+// Note that sendfile for windows does not suppport >2GB file.
+func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) {
+ var n int64 = 0 // by default, copy until EOF
+
+ lr, ok := r.(*io.LimitedReader)
+ if ok {
+ n, r = lr.N, lr.R
+ if n <= 0 {
+ return 0, nil, true
+ }
+ }
+ f, ok := r.(*os.File)
+ if !ok {
+ return 0, nil, false
+ }
+
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.incref()
+ defer c.decref()
+
+ var o sendfileOp
+ o.Init(c)
+ o.n = uint32(n)
+ o.src = f.Fd()
+ done, err := iosrv.ExecIO(&o, 0)
+ if err != nil {
+ return 0, err, false
+ }
+ if lr != nil {
+ lr.N -= int64(done)
+ }
+ return int64(done), nil, true
+}
diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
index 075748b83b0..7d7f7fc01c4 100644
--- a/libgo/go/net/server_test.go
+++ b/libgo/go/net/server_test.go
@@ -92,15 +92,22 @@ func connect(t *testing.T, network, addr string, isEmpty bool) {
}
func doTest(t *testing.T, network, listenaddr, dialaddr string) {
- t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr)
+ t.Logf("Test %q %q %q\n", network, listenaddr, dialaddr)
+ switch listenaddr {
+ case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skip wildcard listen during short test")
+ return
+ }
+ }
listening := make(chan string)
done := make(chan int)
- if network == "tcp" {
+ if network == "tcp" || network == "tcp4" || network == "tcp6" {
listenaddr += ":0" // any available port
}
go runServe(t, network, listenaddr, listening, done)
addr := <-listening // wait for server to start
- if network == "tcp" {
+ if network == "tcp" || network == "tcp4" || network == "tcp6" {
dialaddr += addr[strings.LastIndex(addr, ":"):]
}
connect(t, network, dialaddr, false)
@@ -108,16 +115,39 @@ func doTest(t *testing.T, network, listenaddr, dialaddr string) {
}
func TestTCPServer(t *testing.T) {
+ doTest(t, "tcp", "", "127.0.0.1")
+ doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
doTest(t, "tcp", "127.0.0.1", "127.0.0.1")
- if kernelSupportsIPv6() {
+ doTest(t, "tcp4", "", "127.0.0.1")
+ doTest(t, "tcp4", "0.0.0.0", "127.0.0.1")
+ doTest(t, "tcp4", "127.0.0.1", "127.0.0.1")
+ if supportsIPv6 {
+ doTest(t, "tcp", "", "[::1]")
+ doTest(t, "tcp", "[::]", "[::1]")
doTest(t, "tcp", "[::1]", "[::1]")
+ doTest(t, "tcp6", "", "[::1]")
+ doTest(t, "tcp6", "[::]", "[::1]")
+ doTest(t, "tcp6", "[::1]", "[::1]")
+ }
+ if supportsIPv6 && supportsIPv4map {
+ doTest(t, "tcp", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp", "[::]", "127.0.0.1")
+ doTest(t, "tcp4", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp6", "", "127.0.0.1")
+ doTest(t, "tcp6", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp6", "[::]", "127.0.0.1")
doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp", "[::ffff:127.0.0.1]", "127.0.0.1")
+ doTest(t, "tcp4", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp4", "[::ffff:127.0.0.1]", "127.0.0.1")
+ doTest(t, "tcp6", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp6", "[::ffff:127.0.0.1]", "127.0.0.1")
}
}
func TestUnixServer(t *testing.T) {
- // "unix" sockets are not supported on windows.
- if runtime.GOOS == "windows" {
+ // "unix" sockets are not supported on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
os.Remove("/tmp/gotest.net")
@@ -186,7 +216,7 @@ func TestUDPServer(t *testing.T) {
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() {
+ if supportsIPv6 && supportsIPv4map {
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)
@@ -195,8 +225,8 @@ func TestUDPServer(t *testing.T) {
}
func TestUnixDatagramServer(t *testing.T) {
- // "unix" sockets are not supported on windows.
- if runtime.GOOS == "windows" {
+ // "unix" sockets are not supported on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
for _, isEmpty := range []bool{false} {
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
index 21bd5f03e89..821716e43bd 100644
--- a/libgo/go/net/sock.go
+++ b/libgo/go/net/sock.go
@@ -7,6 +7,7 @@
package net
import (
+ "io"
"os"
"reflect"
"syscall"
@@ -49,8 +50,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
if ra != nil {
if err = fd.connect(ra); err != nil {
- fd.sysfd = -1
- closesocket(s)
+ fd.Close()
return nil, err
}
}
@@ -64,25 +64,25 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
return fd, nil
}
-func setsockoptInt(fd, level, opt int, value int) os.Error {
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, opt, value))
+func setsockoptInt(fd *netFD, level, opt int, value int) os.Error {
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, level, opt, value))
}
-func setsockoptNsec(fd, level, opt int, nsec int64) os.Error {
+func setsockoptNsec(fd *netFD, level, opt int, nsec int64) os.Error {
var tv = syscall.NsecToTimeval(nsec)
- return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd, level, opt, &tv))
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd.sysfd, 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)
+ return setsockoptInt(fd, 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)
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
}
func setReadTimeout(fd *netFD, nsec int64) os.Error {
@@ -105,7 +105,7 @@ func setTimeout(fd *netFD, nsec int64) os.Error {
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))
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
}
func bindToDevice(fd *netFD, dev string) os.Error {
@@ -116,19 +116,19 @@ func bindToDevice(fd *netFD, dev string) os.Error {
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))
+ return setsockoptInt(fd, 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))
+ return setsockoptInt(fd, 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))
+ return setsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
}
func setLinger(fd *netFD, sec int) os.Error {
@@ -154,15 +154,13 @@ 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
- }
+type writerOnly struct {
+ io.Writer
+}
- return "", &UnknownSocketError{sa}
+// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
+// applicable.
+func genericReadFrom(w io.Writer, r io.Reader) (n int64, err os.Error) {
+ // Use wrapper to hide existing r.ReadFrom from io.Copy.
+ return io.Copy(writerOnly{w}, r)
}
diff --git a/libgo/go/net/sock_windows.go b/libgo/go/net/sock_windows.go
index e17c60b98b6..c6dbd046567 100644
--- a/libgo/go/net/sock_windows.go
+++ b/libgo/go/net/sock_windows.go
@@ -10,7 +10,7 @@ import (
"syscall"
)
-func setKernelSpecificSockopt(s, f int) {
+func setKernelSpecificSockopt(s syscall.Handle, f int) {
// Allow reuse of recently-used addresses and ports.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go
index d9aa7cf19a5..f5c0a278107 100644
--- a/libgo/go/net/tcpsock.go
+++ b/libgo/go/net/tcpsock.go
@@ -8,19 +8,8 @@ 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
@@ -37,258 +26,15 @@ func (a *TCPAddr) String() string {
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
+// numeric addresses on the network net, which must be "tcp",
+// "tcp4" or "tcp6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]:80".
-func ResolveTCPAddr(network, addr string) (*TCPAddr, os.Error) {
- ip, port, err := hostPortToIP(network, addr)
+func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error) {
+ ip, port, err := hostPortToIP(net, 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 connects to the remote address raddr on the network net,
-// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
-// as the local address for the connection.
-func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err 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/tcpsock_plan9.go b/libgo/go/net/tcpsock_plan9.go
new file mode 100644
index 00000000000..f4f6e9fee16
--- /dev/null
+++ b/libgo/go/net/tcpsock_plan9.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.
+
+// TCP for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// TCPConn is an implementation of the Conn interface
+// for TCP network connections.
+type TCPConn struct {
+ plan9Conn
+}
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+ }
+ c1, err := dialPlan9(net, laddr, raddr)
+ if err != nil {
+ return
+ }
+ return &TCPConn{*c1}, nil
+}
+
+// TCPListener is a TCP network listener.
+// Clients should typically use variables of type Listener
+// instead of assuming TCP.
+type TCPListener struct {
+ plan9Listener
+}
+
+// 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) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "tcp", nil, errMissingAddress}
+ }
+ l1, err := listenPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ return &TCPListener{*l1}, nil
+}
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
new file mode 100644
index 00000000000..5560301b40f
--- /dev/null
+++ b/libgo/go/net/tcpsock_posix.go
@@ -0,0 +1,283 @@
+// Copyright 2009 The Go 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 (
+ "io"
+ "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
+}
+
+func (a *TCPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != 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
+}
+
+// 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)
+}
+
+// ReadFrom implements the io.ReaderFrom ReadFrom method.
+func (c *TCPConn) ReadFrom(r io.Reader) (int64, os.Error) {
+ if n, err, handled := sendFile(c.fd, r); handled {
+ return n, err
+ }
+ return genericReadFrom(c, r)
+}
+
+// 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 connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err 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 }
+
+// SetTimeout sets the deadline associated with the listener
+func (l *TCPListener) SetTimeout(nsec int64) os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return setTimeout(l.fd, nsec)
+}
+
+// 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/reader.go b/libgo/go/net/textproto/reader.go
index ac1278689a4..ce0ddc73f84 100644
--- a/libgo/go/net/textproto/reader.go
+++ b/libgo/go/net/textproto/reader.go
@@ -7,7 +7,6 @@ package textproto
import (
"bufio"
"bytes"
- "container/vector"
"io"
"io/ioutil"
"os"
@@ -33,22 +32,25 @@ func NewReader(r *bufio.Reader) *Reader {
// 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()
+ line, err := r.readLineSlice()
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--
- }
+ line, err := r.readLineSlice()
+ if line != nil {
+ buf := make([]byte, len(line))
+ copy(buf, line)
+ line = buf
}
- return line[0:n], err
+ return line, err
+}
+
+func (r *Reader) readLineSlice() ([]byte, os.Error) {
+ r.closeDot()
+ line, _, err := r.R.ReadLine()
+ return line, err
}
// ReadContinuedLine reads a possibly continued line from r,
@@ -71,7 +73,7 @@ func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
// A line consisting of only white space is never continued.
//
func (r *Reader) ReadContinuedLine() (string, os.Error) {
- line, err := r.ReadContinuedLineBytes()
+ line, err := r.readContinuedLineSlice()
return string(line), err
}
@@ -92,8 +94,18 @@ func trim(s []byte) []byte {
// ReadContinuedLineBytes is like ReadContinuedLine but
// returns a []byte instead of a string.
func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
+ line, err := r.readContinuedLineSlice()
+ if line != nil {
+ buf := make([]byte, len(line))
+ copy(buf, line)
+ line = buf
+ }
+ return line, err
+}
+
+func (r *Reader) readContinuedLineSlice() ([]byte, os.Error) {
// Read the first line.
- line, err := r.ReadLineBytes()
+ line, err := r.readLineSlice()
if err != nil {
return line, err
}
@@ -102,6 +114,13 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
}
line = trim(line)
+ copied := false
+ if r.R.Buffered() < 1 {
+ // ReadByte will flush the buffer; make a copy of the slice.
+ copied = true
+ line = append([]byte(nil), line...)
+ }
+
// Look for a continuation line.
c, err := r.R.ReadByte()
if err != nil {
@@ -114,6 +133,11 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
return line, nil
}
+ if !copied {
+ // The next readLineSlice will invalidate the previous one.
+ line = append(make([]byte, 0, len(line)*2), line...)
+ }
+
// Read continuation lines.
for {
// Consume leading spaces; one already gone.
@@ -128,7 +152,7 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
}
}
var cont []byte
- cont, err = r.ReadLineBytes()
+ cont, err = r.readLineSlice()
cont = trim(cont)
line = append(line, ' ')
line = append(line, cont...)
@@ -237,7 +261,7 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.
// 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
+// in text protocols such as 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
@@ -375,7 +399,7 @@ 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 v []string
var err os.Error
for {
var line string
@@ -394,7 +418,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
}
line = line[1:]
}
- v.Push(line)
+ v = append(v, line)
}
return v, err
}
@@ -422,7 +446,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
m := make(MIMEHeader)
for {
- kv, err := r.ReadContinuedLineBytes()
+ kv, err := r.readContinuedLineSlice()
if len(kv) == 0 {
return m, err
}
@@ -441,9 +465,7 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
}
value := string(kv[i:])
- v := vector.StringVector(m[key])
- v.Push(value)
- m[key] = v
+ m[key] = append(m[key], value)
if err != nil {
return m, err
diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go
index 67684471b72..3dfa71675f9 100644
--- a/libgo/go/net/udpsock.go
+++ b/libgo/go/net/udpsock.go
@@ -8,19 +8,8 @@ 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
@@ -37,286 +26,15 @@ func (a *UDPAddr) String() string {
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
+// numeric addresses on the network net, which must be "udp",
+// "udp4" or "udp6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]:80".
-func ResolveUDPAddr(network, addr string) (*UDPAddr, os.Error) {
- ip, port, err := hostPortToIP(network, addr)
+func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error) {
+ ip, port, err := hostPortToIP(net, 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() }
-
-var errInvalidMulticast = os.ErrorString("invalid IPv4 multicast address")
-
-// JoinGroup joins the IPv4 multicast group named by addr.
-// The UDPConn must use the "udp4" network.
-func (c *UDPConn) JoinGroup(addr IP) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- ip := addr.To4()
- if ip == nil {
- return &OpError{"joingroup", "udp", &IPAddr{ip}, errInvalidMulticast}
- }
- mreq := &syscall.IpMreq{
- Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
- }
- err := os.NewSyscallError("setsockopt", syscall.SetsockoptIpMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
- if err != nil {
- return &OpError{"joingroup", "udp", &IPAddr{ip}, err}
- }
- return nil
-}
-
-// LeaveGroup exits the IPv4 multicast group named by addr.
-func (c *UDPConn) LeaveGroup(addr IP) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- ip := addr.To4()
- if ip == nil {
- return &OpError{"leavegroup", "udp", &IPAddr{ip}, errInvalidMulticast}
- }
- mreq := &syscall.IpMreq{
- Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
- }
- err := os.NewSyscallError("setsockopt", syscall.SetsockoptIpMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
- if err != nil {
- return &OpError{"leavegroup", "udp", &IPAddr{ip}, err}
- }
- return nil
-}
diff --git a/libgo/go/net/udpsock_plan9.go b/libgo/go/net/udpsock_plan9.go
new file mode 100644
index 00000000000..bb7196041a4
--- /dev/null
+++ b/libgo/go/net/udpsock_plan9.go
@@ -0,0 +1,187 @@
+// Copyright 2009 The Go 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 for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// UDPConn is the implementation of the Conn and PacketConn
+// interfaces for UDP network connections.
+type UDPConn struct {
+ plan9Conn
+}
+
+// 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
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, nil, err
+ }
+ }
+ buf := make([]byte, udpHeaderSize+len(b))
+ m, err := c.data.Read(buf)
+ if err != nil {
+ return
+ }
+ if m < udpHeaderSize {
+ return 0, nil, os.NewError("short read reading UDP header")
+ }
+ buf = buf[:m]
+
+ h, buf := unmarshalUDPHeader(buf)
+ n = copy(b, buf)
+ return n, &UDPAddr{h.raddr, int(h.rport)}, nil
+}
+
+// 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
+ }
+ return c.ReadFromUDP(b)
+}
+
+// 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
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ h := new(udpHeader)
+ h.raddr = addr.IP.To16()
+ h.laddr = c.laddr.(*UDPAddr).IP.To16()
+ h.ifcaddr = IPv6zero // ignored (receive only)
+ h.rport = uint16(addr.Port)
+ h.lport = uint16(c.laddr.(*UDPAddr).Port)
+
+ buf := make([]byte, udpHeaderSize+len(b))
+ i := copy(buf, h.Bytes())
+ copy(buf[i:], b)
+ return c.data.Write(buf)
+}
+
+// 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}
+ }
+ c1, err := dialPlan9(net, laddr, raddr)
+ if err != nil {
+ return
+ }
+ return &UDPConn{*c1}, nil
+}
+
+const udpHeaderSize = 16*3 + 2*2
+
+type udpHeader struct {
+ raddr, laddr, ifcaddr IP
+ rport, lport uint16
+}
+
+func (h *udpHeader) Bytes() []byte {
+ b := make([]byte, udpHeaderSize)
+ i := 0
+ i += copy(b[i:i+16], h.raddr)
+ i += copy(b[i:i+16], h.laddr)
+ i += copy(b[i:i+16], h.ifcaddr)
+ b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2
+ b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2
+ return b
+}
+
+func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
+ h := new(udpHeader)
+ h.raddr, b = IP(b[:16]), b[16:]
+ h.laddr, b = IP(b[:16]), b[16:]
+ h.ifcaddr, b = IP(b[:16]), b[16:]
+ h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
+ h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
+ return h, b
+}
+
+// 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}
+ }
+ l, err := listenPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ _, err = l.ctl.WriteString("headers")
+ if err != nil {
+ return
+ }
+ return &UDPConn{*l.plan9Conn()}, nil
+}
+
+// JoinGroup joins the IPv4 multicast group named by addr.
+// The UDPConn must use the "udp4" network.
+func (c *UDPConn) JoinGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// LeaveGroup exits the IPv4 multicast group named by addr.
+func (c *UDPConn) LeaveGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go
new file mode 100644
index 00000000000..d4ea056f3c7
--- /dev/null
+++ b/libgo/go/net/udpsock_posix.go
@@ -0,0 +1,294 @@
+// Copyright 2009 The Go 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
+}
+
+func (a *UDPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != 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
+}
+
+// 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() }
+
+var errInvalidMulticast = os.NewError("invalid IPv4 multicast address")
+
+// JoinGroup joins the IPv4 multicast group named by addr.
+// The UDPConn must use the "udp4" network.
+func (c *UDPConn) JoinGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ ip := addr.To4()
+ if ip == nil {
+ return &OpError{"joingroup", "udp", &IPAddr{ip}, errInvalidMulticast}
+ }
+ mreq := &syscall.IPMreq{
+ Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
+ }
+ err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
+ if err != nil {
+ return &OpError{"joingroup", "udp", &IPAddr{ip}, err}
+ }
+ return nil
+}
+
+// LeaveGroup exits the IPv4 multicast group named by addr.
+func (c *UDPConn) LeaveGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ ip := addr.To4()
+ if ip == nil {
+ return &OpError{"leavegroup", "udp", &IPAddr{ip}, errInvalidMulticast}
+ }
+ mreq := &syscall.IPMreq{
+ Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
+ }
+ err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
+ if err != nil {
+ return &OpError{"leavegroup", "udp", &IPAddr{ip}, err}
+ }
+ return nil
+}
diff --git a/libgo/go/net/unixsock.go b/libgo/go/net/unixsock.go
index 8c26a7bafd5..d5040f9a297 100644
--- a/libgo/go/net/unixsock.go
+++ b/libgo/go/net/unixsock.go
@@ -8,109 +8,14 @@ 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
@@ -143,307 +48,3 @@ func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) {
}
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/net/unixsock_plan9.go b/libgo/go/net/unixsock_plan9.go
new file mode 100644
index 00000000000..7e212df8a3b
--- /dev/null
+++ b/libgo/go/net/unixsock_plan9.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.
+
+// Unix domain sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// UnixConn is an implementation of the Conn interface
+// for connections to Unix domain sockets.
+type UnixConn bool
+
+// 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) {
+ return 0, os.EPLAN9
+}
+
+// Write implements the net.Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Close closes the Unix domain connection.
+func (c *UnixConn) Close() os.Error {
+ return os.EPLAN9
+}
+
+// LocalAddr returns the local network address, a *UnixAddr.
+// Unlike in other protocols, LocalAddr is usually nil for dialed connections.
+func (c *UnixConn) LocalAddr() Addr {
+ return nil
+}
+
+// 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 {
+ return nil
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UnixConn) SetTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// 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) {
+ return nil, os.EPLAN9
+}
+
+// UnixListener is a Unix domain socket listener.
+// Clients should typically use variables of type Listener
+// instead of assuming Unix domain sockets.
+type UnixListener bool
+
+// 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) {
+ return nil, os.EPLAN9
+}
+
+// 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) {
+ return nil, os.EPLAN9
+}
+
+// Close stops listening on the Unix address.
+// Already accepted connections are not closed.
+func (l *UnixListener) Close() os.Error {
+ return os.EPLAN9
+}
+
+// Addr returns the listener's network address.
+func (l *UnixListener) Addr() Addr { return nil }
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
new file mode 100644
index 00000000000..38c6fe9eb1e
--- /dev/null
+++ b/libgo/go/net/unixsock_posix.go
@@ -0,0 +1,418 @@
+// Copyright 2009 The Go 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}
+}
+
+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 ""
+}
+
+// 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 }
+
+// SetTimeout sets the deadline associated wuth the listener
+func (l *UnixListener) SetTimeout(nsec int64) (err os.Error) {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return setTimeout(l.fd, nsec)
+}
+
+// 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
index a319391bf16..ac1ca12f5ff 100644
--- a/libgo/go/netchan/common.go
+++ b/libgo/go/netchan/common.go
@@ -153,7 +153,7 @@ func (cs *clientSet) drain(timeout int64) os.Error {
break
}
if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
- return os.ErrorString("timeout")
+ return os.NewError("timeout")
}
time.Sleep(100 * 1e6) // 100 milliseconds
}
@@ -186,7 +186,7 @@ func (cs *clientSet) sync(timeout int64) os.Error {
break
}
if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
- return os.ErrorString("timeout")
+ return os.NewError("timeout")
}
time.Sleep(100 * 1e6) // 100 milliseconds
}
diff --git a/libgo/go/netchan/export.go b/libgo/go/netchan/export.go
index 1e5ccdb5cba..7df73651536 100644
--- a/libgo/go/netchan/export.go
+++ b/libgo/go/netchan/export.go
@@ -343,20 +343,20 @@ func (exp *Exporter) Sync(timeout int64) os.Error {
func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
chanType := reflect.TypeOf(chT)
if chanType.Kind() != reflect.Chan {
- return reflect.Value{}, os.ErrorString("not a channel")
+ return reflect.Value{}, os.NewError("not a channel")
}
if dir != Send && dir != Recv {
- return reflect.Value{}, os.ErrorString("unknown channel direction")
+ return reflect.Value{}, os.NewError("unknown channel direction")
}
switch chanType.ChanDir() {
case reflect.BothDir:
case reflect.SendDir:
if dir != Recv {
- return reflect.Value{}, os.ErrorString("to import/export with Send, must provide <-chan")
+ return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
}
case reflect.RecvDir:
if dir != Send {
- return reflect.Value{}, os.ErrorString("to import/export with Recv, must provide chan<-")
+ return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
}
}
return reflect.ValueOf(chT), nil
@@ -376,7 +376,7 @@ func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
defer exp.mu.Unlock()
_, present := exp.names[name]
if present {
- return os.ErrorString("channel name already being exported:" + name)
+ return os.NewError("channel name already being exported:" + name)
}
exp.names[name] = &chanDir{ch, dir}
return nil
@@ -393,7 +393,7 @@ func (exp *Exporter) Hangup(name string) os.Error {
// TODO drop all instances of channel from client sets
exp.mu.Unlock()
if !ok {
- return os.ErrorString("netchan export: hangup: no such channel: " + name)
+ return os.NewError("netchan export: hangup: no such channel: " + name)
}
chDir.ch.Close()
return nil
diff --git a/libgo/go/netchan/import.go b/libgo/go/netchan/import.go
index 0a700ca2b99..ec17d97774b 100644
--- a/libgo/go/netchan/import.go
+++ b/libgo/go/netchan/import.go
@@ -11,6 +11,7 @@ import (
"os"
"reflect"
"sync"
+ "time"
)
// Import
@@ -31,6 +32,9 @@ type Importer struct {
chans map[int]*netChan
errors chan os.Error
maxId int
+ mu sync.Mutex // protects remaining fields
+ unacked int64 // number of unacknowledged sends.
+ seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
}
// NewImporter creates a new Importer object to import a set of channels
@@ -42,6 +46,7 @@ func NewImporter(conn io.ReadWriter) *Importer {
imp.chans = make(map[int]*netChan)
imp.names = make(map[string]*netChan)
imp.errors = make(chan os.Error, 10)
+ imp.unacked = 0
go imp.run()
return imp
}
@@ -80,8 +85,10 @@ func (imp *Importer) run() {
for {
*hdr = header{}
if e := imp.decode(hdrValue); e != nil {
- impLog("header:", e)
- imp.shutdown()
+ if e != os.EOF {
+ impLog("header:", e)
+ imp.shutdown()
+ }
return
}
switch hdr.PayloadType {
@@ -95,7 +102,7 @@ func (imp *Importer) run() {
if err.Error != "" {
impLog("response error:", err.Error)
select {
- case imp.errors <- os.ErrorString(err.Error):
+ case imp.errors <- os.NewError(err.Error):
continue // errors are not acknowledged
default:
imp.shutdown()
@@ -114,6 +121,9 @@ func (imp *Importer) run() {
nch := imp.getChan(hdr.Id, true)
if nch != nil {
nch.acked()
+ imp.mu.Lock()
+ imp.unacked--
+ imp.mu.Unlock()
}
continue
default:
@@ -193,7 +203,7 @@ func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size,
defer imp.chanLock.Unlock()
_, present := imp.names[name]
if present {
- return os.ErrorString("channel name already being imported:" + name)
+ return os.NewError("channel name already being imported:" + name)
}
if size < 1 {
size = 1
@@ -220,10 +230,17 @@ func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size,
}
return
}
+ // We hold the lock during transmission to guarantee messages are
+ // sent in order.
+ imp.mu.Lock()
+ imp.unacked++
+ imp.seqLock.Lock()
+ imp.mu.Unlock()
if err = imp.encode(hdr, payData, val.Interface()); err != nil {
impLog("error encoding client send:", err)
return
}
+ imp.seqLock.Unlock()
}
}()
}
@@ -237,10 +254,34 @@ func (imp *Importer) Hangup(name string) os.Error {
defer imp.chanLock.Unlock()
nc := imp.names[name]
if nc == nil {
- return os.ErrorString("netchan import: hangup: no such channel: " + name)
+ return os.NewError("netchan import: hangup: no such channel: " + name)
}
imp.names[name] = nil, false
imp.chans[nc.id] = nil, false
nc.close()
return nil
}
+
+func (imp *Importer) unackedCount() int64 {
+ imp.mu.Lock()
+ n := imp.unacked
+ imp.mu.Unlock()
+ return n
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any server and possibly including those sent while
+// Drain was executing, have been received by the exporter. In short, it
+// waits until all the importer's messages have been received.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (imp *Importer) Drain(timeout int64) os.Error {
+ startTime := time.Nanoseconds()
+ for imp.unackedCount() > 0 {
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.NewError("timeout")
+ }
+ time.Sleep(100 * 1e6)
+ }
+ return nil
+}
diff --git a/libgo/go/netchan/netchan_test.go b/libgo/go/netchan/netchan_test.go
index fd4d8f780d9..8c0f9a6e4b7 100644
--- a/libgo/go/netchan/netchan_test.go
+++ b/libgo/go/netchan/netchan_test.go
@@ -178,6 +178,16 @@ func TestExportDrain(t *testing.T) {
<-done
}
+// Not a great test but it does at least invoke Drain.
+func TestImportDrain(t *testing.T) {
+ exp, imp := pair(t)
+ expDone := make(chan bool)
+ go exportReceive(exp, t, expDone)
+ <-expDone
+ importSend(imp, closeCount, t, nil)
+ imp.Drain(0)
+}
+
// Not a great test but it does at least invoke Sync.
func TestExportSync(t *testing.T) {
exp, imp := pair(t)
diff --git a/libgo/go/old/template/doc.go b/libgo/go/old/template/doc.go
new file mode 100644
index 00000000000..e778d801dab
--- /dev/null
+++ b/libgo/go/old/template/doc.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.
+
+/*
+ Package template implements 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())
+
+ If Field is a struct field or method name, it must be an exported
+ (capitalized) name.
+
+ Major constructs ({} are the default delimiters for template actions;
+ [] are the notation in this comment for 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}
+ {field|formatter1|formatter2}
+
+ 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 the field value is a pointer, leading asterisks indicate
+ that the value to be inserted should be evaluated through the
+ pointer. For example, if x.p is of type *int, {x.p} will
+ insert the value of the pointer but {*x.p} will insert the
+ value of the underlying integer. If the value is nil or not a
+ pointer, asterisks have no effect.
+
+ 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.
+
+ Multiple formatters separated by the pipeline character | are
+ executed sequentially, with each formatter receiving the bytes
+ emitted by the one to its left.
+
+ As well as field names, one may use literals with Go syntax.
+ Integer, floating-point, and string literals are supported.
+ Raw strings may not span newlines.
+
+ The delimiter strings get their default value, "{" and "}", from
+ JSON-template. They may be set to any non-empty, space-free
+ string using the SetDelims method. Their value can be printed
+ in the output using {.meta-left} and {.meta-right}.
+*/
+package template
diff --git a/libgo/go/old/template/execute.go b/libgo/go/old/template/execute.go
new file mode 100644
index 00000000000..464b620c98b
--- /dev/null
+++ b/libgo/go/old/template/execute.go
@@ -0,0 +1,346 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code to execute a parsed template.
+
+package template
+
+import (
+ "bytes"
+ "io"
+ "reflect"
+ "strings"
+)
+
+// 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
+ buf [2]bytes.Buffer // alternating buffers used when chaining formatters
+}
+
+func (parent *state) clone(data reflect.Value) *state {
+ return &state{parent: parent, data: data, wr: parent.wr}
+}
+
+// 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.IsValid() {
+ 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; av.Kind() {
+ case reflect.Ptr:
+ v = av.Elem()
+ case reflect.Interface:
+ v = av.Elem()
+ case reflect.Struct:
+ 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.Map:
+ if v := av.MapIndex(reflect.ValueOf(name)); v.IsValid() {
+ return v
+ }
+ return reflect.Zero(typ.Elem())
+ default:
+ return reflect.Value{}
+ }
+ }
+ return v
+}
+
+// indirectPtr returns the item numLevels levels of indirection below the value.
+// It is forgiving: if the value is not a pointer, it returns it rather than giving
+// an error. If the pointer is nil, it is returned as is.
+func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
+ for i := numLevels; v.IsValid() && i > 0; i++ {
+ if p := v; p.Kind() == reflect.Ptr {
+ if p.IsNil() {
+ return v
+ }
+ v = p.Elem()
+ } else {
+ break
+ }
+ }
+ return v
+}
+
+// Walk v through pointers and interfaces, extracting the elements within.
+func indirect(v reflect.Value) reflect.Value {
+loop:
+ for v.IsValid() {
+ switch av := v; av.Kind() {
+ case reflect.Ptr:
+ v = av.Elem()
+ case reflect.Interface:
+ 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. Leading stars indicate
+// levels of indirection to be applied to the value.
+func (t *Template) findVar(st *state, s string) reflect.Value {
+ data := st.data
+ flattenedName := strings.TrimLeft(s, "*")
+ numStars := len(s) - len(flattenedName)
+ s = flattenedName
+ if s == "@" {
+ return indirectPtr(data, numStars)
+ }
+ for _, elem := range strings.Split(s, ".") {
+ // Look up field; data must be a struct or map.
+ data = t.lookup(st, data, elem)
+ if !data.IsValid() {
+ return reflect.Value{}
+ }
+ }
+ return indirectPtr(data, numStars)
+}
+
+// Is there no data to look at?
+func empty(v reflect.Value) bool {
+ v = indirect(v)
+ if !v.IsValid() {
+ return true
+ }
+ switch v.Kind() {
+ case reflect.Bool:
+ return v.Bool() == false
+ case reflect.String:
+ return v.String() == ""
+ case reflect.Struct:
+ return false
+ case reflect.Map:
+ return false
+ case reflect.Array:
+ return v.Len() == 0
+ case reflect.Slice:
+ 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.IsValid() {
+ 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
+}
+
+func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
+ fn := t.formatter(fmt)
+ if fn == nil {
+ t.execError(st, v.linenum, "missing formatter %s for variable", fmt)
+ }
+ fn(wr, fmt, val...)
+}
+
+// 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) {
+ // Resolve field names
+ val := make([]interface{}, len(v.args))
+ for i, arg := range v.args {
+ if name, ok := arg.(fieldName); ok {
+ val[i] = t.varValue(string(name), st).Interface()
+ } else {
+ val[i] = arg
+ }
+ }
+ for i, fmt := range v.fmts[:len(v.fmts)-1] {
+ b := &st.buf[i&1]
+ b.Reset()
+ t.format(b, fmt, val, v, st)
+ val = val[0:1]
+ val[0] = b.Bytes()
+ }
+ t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
+}
+
+// Execute element i. Return next index to execute.
+func (t *Template) executeElement(i int, st *state) int {
+ switch elem := t.elems[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[i]
+ t.execError(st, 0, "internal error: bad directive in execute: %v %T\n", reflect.ValueOf(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.IsValid() {
+ 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.Value {
+ for j := 0; j < v.Type().NumMethod(); j++ {
+ mth := v.Type().Method(j)
+ fv := v.Method(j)
+ ft := fv.Type()
+ // 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 := ft.Out(0)
+ if ct.Kind() != reflect.Chan ||
+ ct.ChanDir()&reflect.RecvDir == 0 {
+ continue
+ }
+ return fv.Call(nil)[0]
+ }
+ return reflect.Value{}
+}
+
+// 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.IsValid() {
+ 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 := field; array.Kind() == reflect.Array || array.Kind() == reflect.Slice {
+ for j := 0; j < array.Len(); j++ {
+ loopBody(st.clone(array.Index(j)))
+ }
+ } else if m := field; m.Kind() == reflect.Map {
+ for _, key := range m.MapKeys() {
+ loopBody(st.clone(m.MapIndex(key)))
+ }
+ } else if ch := iter(field); ch.IsValid() {
+ for {
+ e, ok := ch.Recv()
+ if !ok {
+ 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 space and be non-empty.
+func validDelim(d []byte) bool {
+ if len(d) == 0 {
+ return false
+ }
+ for _, c := range d {
+ if isSpace(c) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/template/format.go b/libgo/go/old/template/format.go
index 9156b080816..9156b080816 100644
--- a/libgo/go/template/format.go
+++ b/libgo/go/old/template/format.go
diff --git a/libgo/go/template/template.go b/libgo/go/old/template/parse.go
index 25320785223..dedf9ad8e9f 100644
--- a/libgo/go/template/template.go
+++ b/libgo/go/old/template/parse.go
@@ -2,95 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/*
- Package template implements data-driven templates for generating textual
- output such as HTML.
+// Code to parse a template.
- 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 the default delimiters for template actions;
- [] are the notation in this comment for 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}
- {field|formatter1|formatter2}
-
- 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 the field value is a pointer, leading asterisks indicate
- that the value to be inserted should be evaluated through the
- pointer. For example, if x.p is of type *int, {x.p} will
- insert the value of the pointer but {*x.p} will insert the
- value of the underlying integer. If the value is nil or not a
- pointer, asterisks have no effect.
-
- 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.
-
- Multiple formatters separated by the pipeline character | are
- executed sequentially, with each formatter receiving the bytes
- emitted by the one to its left.
-
- The delimiter strings get their default value, "{" and "}", from
- JSON-template. They may be set to any non-empty, space-free
- string using the SetDelims method. Their value can be printed
- in the output using {.meta-left} and {.meta-right}.
-*/
package template
import (
- "bytes"
- "container/vector"
"fmt"
"io"
"io/ioutil"
"os"
"reflect"
+ "strconv"
"strings"
"unicode"
"utf8"
@@ -105,6 +27,19 @@ type Error struct {
func (e *Error) String() string { return fmt.Sprintf("line %d: %s", e.Line, e.Msg) }
+// 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)
+ }
+ }
+}
+
// Most of the literals are aces.
var lbrace = []byte{'{'}
var rbrace = []byte{'}'}
@@ -151,10 +86,13 @@ type literalElement struct {
// A variable invocation to be evaluated
type variableElement struct {
linenum int
- word []string // The fields in the invocation.
- fmts []string // Names of formatters to apply. len(fmts) > 0
+ args []interface{} // The fields and literals in the invocation.
+ fmts []string // Names of formatters to apply. len(fmts) > 0
}
+// A variableElement arg to be evaluated as a field name
+type fieldName string
+
// A .section block, possibly with a .or
type sectionElement struct {
linenum int // of .section itself
@@ -181,21 +119,7 @@ type Template struct {
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
- buf [2]bytes.Buffer // alternating buffers used when chaining formatters
-}
-
-func (parent *state) clone(data reflect.Value) *state {
- return &state{parent: parent, data: data, wr: parent.wr}
+ elems []interface{}
}
// New creates a new template with the specified formatter map (which
@@ -205,7 +129,7 @@ func New(fmap FormatterMap) *Template {
t.fmap = fmap
t.ldelim = lbrace
t.rdelim = rbrace
- t.elems = new(vector.Vector)
+ t.elems = make([]interface{}, 0, 16)
return t
}
@@ -228,8 +152,8 @@ func isExported(name string) bool {
// -- Lexical analysis
-// Is c a white space character?
-func white(c uint8) bool { return c == ' ' || c == '\t' || c == '\r' || c == '\n' }
+// Is c a space character?
+func isSpace(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 {
@@ -245,6 +169,31 @@ func equal(s []byte, n int, t []byte) bool {
return true
}
+// isQuote returns true if c is a string- or character-delimiting quote character.
+func isQuote(c byte) bool {
+ return c == '"' || c == '`' || c == '\''
+}
+
+// endQuote returns the end quote index for the quoted string that
+// starts at n, or -1 if no matching end quote is found before the end
+// of the line.
+func endQuote(s []byte, n int) int {
+ quote := s[n]
+ for n++; n < len(s); n++ {
+ switch s[n] {
+ case '\\':
+ if quote == '"' || quote == '\'' {
+ n++
+ }
+ case '\n':
+ return -1
+ case quote:
+ return n
+ }
+ }
+ return -1
+}
+
// 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
@@ -259,9 +208,9 @@ func (t *Template) nextItem() []byte {
t.linenum++
i++
}
- // Leading white space up to but not including newline
+ // Leading space up to but not including newline
for i = start; i < len(t.buf); i++ {
- if t.buf[i] == '\n' || !white(t.buf[i]) {
+ if t.buf[i] == '\n' || !isSpace(t.buf[i]) {
break
}
}
@@ -282,6 +231,14 @@ func (t *Template) nextItem() []byte {
if t.buf[i] == '\n' {
break
}
+ if isQuote(t.buf[i]) {
+ i = endQuote(t.buf, i)
+ if i == -1 {
+ t.parseError("unmatched quote")
+ return nil
+ }
+ continue
+ }
if equal(t.buf, i, t.rdelim) {
i += len(t.rdelim)
right = i
@@ -298,7 +255,7 @@ func (t *Template) nextItem() []byte {
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++ {
+ for j := right; j < len(t.buf) && isSpace(t.buf[j]); j++ {
if t.buf[j] == '\n' {
// Yes it is. Drop the surrounding space and return the {.foo}
t.linenum++
@@ -310,7 +267,7 @@ func (t *Template) nextItem() []byte {
}
// No it's not. If there's leading space, return that.
if leadingSpace {
- // not trimming space: return leading white space if there is some.
+ // not trimming space: return leading space if there is some.
t.p = left
return t.buf[start:left]
}
@@ -333,23 +290,34 @@ func (t *Template) nextItem() []byte {
return item
}
-// Turn a byte array into a white-space-split array of strings.
+// Turn a byte array into a space-split array of strings,
+// taking into account quoted 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++ {
+ for i := 0; i < len(buf); {
+ // One word per loop
+ for i < len(buf) && isSpace(buf[i]) {
+ i++
}
- if start == p { // no text left
+ if i == len(buf) {
break
}
- s = append(s, string(buf[start:p]))
+ // Got a word
+ start := i
+ if isQuote(buf[i]) {
+ i = endQuote(buf, i)
+ if i < 0 {
+ i = len(buf)
+ } else {
+ i++
+ }
+ }
+ // Even with quotes, break on space only. This handles input
+ // such as {""|} and catches quoting mistakes.
+ for i < len(buf) && !isSpace(buf[i]) {
+ i++
+ }
+ s = append(s, string(buf[start:i]))
}
return s
}
@@ -381,11 +349,17 @@ func (t *Template) analyze(item []byte) (tok int, w []string) {
t.parseError("empty directive")
return
}
- if len(w) > 0 && w[0][0] != '.' {
+ first := w[0]
+ if first[0] != '.' {
+ tok = tokVariable
+ return
+ }
+ if len(first) > 1 && first[1] >= '0' && first[1] <= '9' {
+ // Must be a float.
tok = tokVariable
return
}
- switch w[0] {
+ switch first {
case ".meta-left", ".meta-right", ".space", ".tab":
tok = tokLiteral
return
@@ -433,18 +407,38 @@ func (t *Template) formatter(name string) func(io.Writer, string, ...interface{}
// -- Parsing
-// Allocate a new variable-evaluation element.
+// newVariable allocates a new variable-evaluation element.
func (t *Template) newVariable(words []string) *variableElement {
- // After the final space-separated argument, formatters may be specified separated
- // by pipe symbols, for example: {a b c|d|e}
+ formatters := extractFormatters(words)
+ args := make([]interface{}, len(words))
+
+ // Build argument list, processing any literals
+ for i, word := range words {
+ var lerr os.Error
+ switch word[0] {
+ case '"', '`', '\'':
+ v, err := strconv.Unquote(word)
+ if err == nil && word[0] == '\'' {
+ args[i] = []int(v)[0]
+ } else {
+ args[i], lerr = v, err
+ }
- // Until we learn otherwise, formatters contains a single name: "", the default formatter.
- formatters := []string{""}
- lastWord := words[len(words)-1]
- bar := strings.IndexRune(lastWord, '|')
- if bar >= 0 {
- words[len(words)-1] = lastWord[0:bar]
- formatters = strings.Split(lastWord[bar+1:], "|", -1)
+ case '.', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ v, err := strconv.Btoi64(word, 0)
+ if err == nil {
+ args[i] = v
+ } else {
+ v, err := strconv.Atof64(word)
+ args[i], lerr = v, err
+ }
+
+ default:
+ args[i] = fieldName(word)
+ }
+ if lerr != nil {
+ t.parseError("invalid literal: %q: %s", word, lerr)
+ }
}
// We could remember the function address here and avoid the lookup later,
@@ -457,7 +451,40 @@ func (t *Template) newVariable(words []string) *variableElement {
t.parseError("unknown formatter: %q", f)
}
}
- return &variableElement{t.linenum, words, formatters}
+
+ return &variableElement{t.linenum, args, formatters}
+}
+
+// extractFormatters extracts a list of formatters from words.
+// After the final space-separated argument in a variable, formatters may be
+// specified separated by pipe symbols. For example: {a b c|d|e}
+// The words parameter still has the formatters joined by '|' in the last word.
+// extractFormatters splits formatters, replaces the last word with the content
+// found before the first '|' within it, and returns the formatters obtained.
+// If no formatters are found in words, the default formatter is returned.
+func extractFormatters(words []string) (formatters []string) {
+ // "" is the default formatter.
+ formatters = []string{""}
+ if len(words) == 0 {
+ return
+ }
+ var bar int
+ lastWord := words[len(words)-1]
+ if isQuote(lastWord[0]) {
+ end := endQuote([]byte(lastWord), 0)
+ if end < 0 || end+1 == len(lastWord) || lastWord[end+1] != '|' {
+ return
+ }
+ bar = end + 1
+ } else {
+ bar = strings.IndexRune(lastWord, '|')
+ if bar < 0 {
+ return
+ }
+ }
+ words[len(words)-1] = lastWord[0:bar]
+ formatters = strings.Split(lastWord[bar+1:], "|")
+ return
}
// Grab the next item. If it's simple, just append it to the template.
@@ -469,24 +496,24 @@ func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
case tokComment:
return
case tokText:
- t.elems.Push(&textElement{item})
+ t.elems = append(t.elems, &textElement{item})
return
case tokLiteral:
switch w[0] {
case ".meta-left":
- t.elems.Push(&literalElement{t.ldelim})
+ t.elems = append(t.elems, &literalElement{t.ldelim})
case ".meta-right":
- t.elems.Push(&literalElement{t.rdelim})
+ t.elems = append(t.elems, &literalElement{t.rdelim})
case ".space":
- t.elems.Push(&literalElement{space})
+ t.elems = append(t.elems, &literalElement{space})
case ".tab":
- t.elems.Push(&literalElement{tab})
+ t.elems = append(t.elems, &literalElement{tab})
default:
t.parseError("internal error: unknown literal: %s", w[0])
}
return
case tokVariable:
- t.elems.Push(t.newVariable(w))
+ t.elems = append(t.elems, t.newVariable(w))
return
}
return false, tok, w
@@ -496,11 +523,11 @@ func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
func (t *Template) parseRepeated(words []string) *repeatedElement {
r := new(repeatedElement)
- t.elems.Push(r)
+ t.elems = append(t.elems, r)
r.linenum = t.linenum
r.field = words[2]
// Scan section, collecting true and false (.or) blocks.
- r.start = t.elems.Len()
+ r.start = len(t.elems)
r.or = -1
r.altstart = -1
r.altend = -1
@@ -523,8 +550,8 @@ Loop:
t.parseError("extra .or in .repeated section")
break Loop
}
- r.altend = t.elems.Len()
- r.or = t.elems.Len()
+ r.altend = len(t.elems)
+ r.or = len(t.elems)
case tokSection:
t.parseSection(w)
case tokRepeated:
@@ -538,26 +565,26 @@ Loop:
t.parseError(".alternates inside .or block in .repeated section")
break Loop
}
- r.altstart = t.elems.Len()
+ r.altstart = len(t.elems)
default:
t.parseError("internal error: unknown repeated section item: %s", item)
break Loop
}
}
if r.altend < 0 {
- r.altend = t.elems.Len()
+ r.altend = len(t.elems)
}
- r.end = t.elems.Len()
+ r.end = len(t.elems)
return r
}
func (t *Template) parseSection(words []string) *sectionElement {
s := new(sectionElement)
- t.elems.Push(s)
+ t.elems = append(t.elems, s)
s.linenum = t.linenum
s.field = words[1]
// Scan section, collecting true and false (.or) blocks.
- s.start = t.elems.Len()
+ s.start = len(t.elems)
s.or = -1
Loop:
for {
@@ -578,7 +605,7 @@ Loop:
t.parseError("extra .or in .section")
break Loop
}
- s.or = t.elems.Len()
+ s.or = len(t.elems)
case tokSection:
t.parseSection(w)
case tokRepeated:
@@ -589,7 +616,7 @@ Loop:
t.parseError("internal error: unknown section item: %s", item)
}
}
- s.end = t.elems.Len()
+ s.end = len(t.elems)
return s
}
@@ -618,334 +645,6 @@ func (t *Template) parse() {
// -- 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.IsValid() {
- 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; av.Kind() {
- case reflect.Ptr:
- v = av.Elem()
- case reflect.Interface:
- v = av.Elem()
- case reflect.Struct:
- 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.Map:
- if v := av.MapIndex(reflect.ValueOf(name)); v.IsValid() {
- return v
- }
- return reflect.Zero(typ.Elem())
- default:
- return reflect.Value{}
- }
- }
- return v
-}
-
-// indirectPtr returns the item numLevels levels of indirection below the value.
-// It is forgiving: if the value is not a pointer, it returns it rather than giving
-// an error. If the pointer is nil, it is returned as is.
-func indirectPtr(v reflect.Value, numLevels int) reflect.Value {
- for i := numLevels; v.IsValid() && i > 0; i++ {
- if p := v; p.Kind() == reflect.Ptr {
- if p.IsNil() {
- return v
- }
- v = p.Elem()
- } else {
- break
- }
- }
- return v
-}
-
-// Walk v through pointers and interfaces, extracting the elements within.
-func indirect(v reflect.Value) reflect.Value {
-loop:
- for v.IsValid() {
- switch av := v; av.Kind() {
- case reflect.Ptr:
- v = av.Elem()
- case reflect.Interface:
- 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. Leading stars indicate
-// levels of indirection to be applied to the value.
-func (t *Template) findVar(st *state, s string) reflect.Value {
- data := st.data
- flattenedName := strings.TrimLeft(s, "*")
- numStars := len(s) - len(flattenedName)
- s = flattenedName
- if s == "@" {
- return indirectPtr(data, numStars)
- }
- 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.IsValid() {
- return reflect.Value{}
- }
- }
- return indirectPtr(data, numStars)
-}
-
-// Is there no data to look at?
-func empty(v reflect.Value) bool {
- v = indirect(v)
- if !v.IsValid() {
- return true
- }
- switch v.Kind() {
- case reflect.Bool:
- return v.Bool() == false
- case reflect.String:
- return v.String() == ""
- case reflect.Struct:
- return false
- case reflect.Map:
- return false
- case reflect.Array:
- return v.Len() == 0
- case reflect.Slice:
- 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.IsValid() {
- 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
-}
-
-func (t *Template) format(wr io.Writer, fmt string, val []interface{}, v *variableElement, st *state) {
- fn := t.formatter(fmt)
- if fn == nil {
- t.execError(st, v.linenum, "missing formatter %s for variable %s", fmt, v.word[0])
- }
- fn(wr, fmt, val...)
-}
-
-// 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) {
- // 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()
- }
-
- for i, fmt := range v.fmts[:len(v.fmts)-1] {
- b := &st.buf[i&1]
- b.Reset()
- t.format(b, fmt, val, v, st)
- val = val[0:1]
- val[0] = b.Bytes()
- }
- t.format(st.wr, v.fmts[len(v.fmts)-1], val, v, st)
-}
-
-// 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.ValueOf(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.IsValid() {
- 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.Value {
- for j := 0; j < v.Type().NumMethod(); j++ {
- mth := v.Type().Method(j)
- fv := v.Method(j)
- ft := fv.Type()
- // 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 := ft.Out(0)
- if ct.Kind() != reflect.Chan ||
- ct.ChanDir()&reflect.RecvDir == 0 {
- continue
- }
- return fv.Call(nil)[0]
- }
- return reflect.Value{}
-}
-
-// 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.IsValid() {
- 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 := field; array.Kind() == reflect.Array || array.Kind() == reflect.Slice {
- for j := 0; j < array.Len(); j++ {
- loopBody(st.clone(array.Index(j)))
- }
- } else if m := field; m.Kind() == reflect.Map {
- for _, key := range m.MapKeys() {
- loopBody(st.clone(m.MapIndex(key)))
- }
- } else if ch := iter(field); ch.IsValid() {
- for {
- e, ok := ch.Recv()
- if !ok {
- 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
@@ -983,7 +682,7 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
val := reflect.ValueOf(data)
defer checkError(&err)
t.p = 0
- t.execute(0, t.elems.Len(), &state{parent: nil, data: val, wr: wr})
+ t.execute(0, len(t.elems), &state{parent: nil, data: val, wr: wr})
return nil
}
diff --git a/libgo/go/template/template_test.go b/libgo/go/old/template/template_test.go
index d21a5397a15..eae8011eb38 100644
--- a/libgo/go/template/template_test.go
+++ b/libgo/go/old/template/template_test.go
@@ -94,10 +94,15 @@ func multiword(w io.Writer, format string, value ...interface{}) {
}
}
+func printf(w io.Writer, format string, v ...interface{}) {
+ io.WriteString(w, fmt.Sprintf(v[0].(string), v[1:]...))
+}
+
var formatters = FormatterMap{
"uppercase": writer(uppercase),
"+1": writer(plus1),
"multiword": multiword,
+ "printf": printf,
}
var tests = []*Test{
@@ -138,6 +143,36 @@ var tests = []*Test{
out: "nil pointer: <nil>=77\n",
},
+ &Test{
+ in: `{"Strings" ":"} {""} {"|"} {"\t\u0123 \x23\\"} {"\"}{\\"}`,
+
+ out: "Strings: | \t\u0123 \x23\\ \"}{\\",
+ },
+
+ &Test{
+ in: "{`Raw strings` `:`} {``} {`|`} {`\\t\\u0123 \\x23\\`} {`}{\\`}",
+
+ out: "Raw strings: | \\t\\u0123 \\x23\\ }{\\",
+ },
+
+ &Test{
+ in: "Characters: {'a'} {'\\u0123'} {' '} {'{'} {'|'} {'}'}",
+
+ out: "Characters: 97 291 32 123 124 125",
+ },
+
+ &Test{
+ in: "Integers: {1} {-2} {+42} {0777} {0x0a}",
+
+ out: "Integers: 1 -2 42 511 10",
+ },
+
+ &Test{
+ in: "Floats: {.5} {-.5} {1.1} {-2.2} {+42.1} {1e10} {1.2e-3} {1.2e3} {-1.2e3}",
+
+ out: "Floats: 0.5 -0.5 1.1 -2.2 42.1 1e+10 0.0012 1200 -1200",
+ },
+
// Method at top level
&Test{
in: "ptrmethod={PointerMethod}\n",
@@ -224,7 +259,6 @@ var tests = []*Test{
out: "77",
},
-
// Repeated
&Test{
in: "{.section Pdata }\n" +
@@ -403,7 +437,6 @@ var tests = []*Test{
"pointedToString\n",
},
-
// Interface values
&Test{
@@ -723,6 +756,14 @@ var formatterTests = []Test{
in: "{Integer|||||}", // empty string is a valid formatter
out: "77",
},
+ {
+ in: `{"%.02f 0x%02X" 1.1 10|printf}`,
+ out: "1.10 0x0A",
+ },
+ {
+ in: `{""|}{""||}{""|printf}`, // Issue #1896.
+ out: "",
+ },
}
func TestFormatters(t *testing.T) {
diff --git a/libgo/go/os/dir.go b/libgo/go/os/dir.go
index b3b5d3e37dc..5f383c12fda 100644
--- a/libgo/go/os/dir.go
+++ b/libgo/go/os/dir.go
@@ -27,8 +27,19 @@ func clen(n []byte) int {
var elen int;
-// Negative count means read until EOF.
-func (file *File) Readdirnames(count int) (names []string, err Error) {
+// Readdirnames reads and returns a slice of names from the directory f.
+//
+// If n > 0, Readdirnames returns at most n names. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdirnames returns all the names from the directory in
+// a single slice. In this case, if Readdirnames succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdirnames returns the names read until that point and
+// a non-nil error.
+func (file *File) Readdirnames(n int) (names []string, err Error) {
if elen == 0 {
var dummy syscall.Dirent;
elen = (unsafe.Offsetof(dummy.Name) +
@@ -44,10 +55,12 @@ func (file *File) Readdirnames(count int) (names []string, err Error) {
entry_dirent := unsafe.Pointer(&file.dirinfo.buf[0]).(*syscall.Dirent)
- size := count
+ size := n
if size < 0 {
size = 100
+ n = -1
}
+
names = make([]string, 0, size) // Empty with room to grow.
dir := file.dirinfo.dir
@@ -55,18 +68,24 @@ func (file *File) Readdirnames(count int) (names []string, err Error) {
return names, NewSyscallError("opendir", syscall.GetErrno())
}
- for count != 0 {
+ for n != 0 {
var result *syscall.Dirent
i := libc_readdir_r(dir, entry_dirent, &result)
+ if i != 0 {
+ return names, NewSyscallError("readdir_r", i)
+ }
if result == nil {
- break
+ break // EOF
}
var name = string(result.Name[0:clen(result.Name[0:])])
if name == "." || name == ".." { // Useless names
continue
}
- count--
names = append(names, name)
+ n--
+ }
+ if n >= 0 && len(names) == 0 {
+ return names, EOF
}
return names, nil
}
diff --git a/libgo/go/os/dir_plan9.go b/libgo/go/os/dir_plan9.go
index d9514191d79..bbc2cb64726 100644
--- a/libgo/go/os/dir_plan9.go
+++ b/libgo/go/os/dir_plan9.go
@@ -9,35 +9,46 @@ import (
)
// Readdir reads the contents of the directory associated with file and
-// returns an array of up to count FileInfo structures, 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) {
+// returns an array of up to n FileInfo structures, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
+// further FileInfos.
+//
+// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdir returns all the FileInfo from the directory in
+// a single slice. In this case, if Readdir succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdir returns the FileInfo read until that point
+// and a non-nil error.
+func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
// If this file has no dirinfo, create one.
if file.dirinfo == nil {
file.dirinfo = new(dirInfo)
}
d := file.dirinfo
- size := count
- if size < 0 {
+ size := n
+ if size <= 0 {
size = 100
+ n = -1
}
result := make([]FileInfo, 0, size) // Empty with room to grow.
- for count != 0 {
+ for n != 0 {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
d.bufp = 0
var e Error
d.nbuf, e = file.Read(d.buf[:])
if e != nil && e != EOF {
- return nil, &PathError{"readdir", file.name, e}
+ return result, &PathError{"readdir", file.name, e}
}
if e == EOF {
break
}
if d.nbuf < syscall.STATFIXLEN {
- return nil, &PathError{"readdir", file.name, Eshortstat}
+ return result, &PathError{"readdir", file.name, Eshortstat}
}
}
@@ -45,39 +56,44 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
m, _ := gbit16(d.buf[d.bufp:])
m += 2
if m < syscall.STATFIXLEN {
- return nil, &PathError{"readdir", file.name, Eshortstat}
+ return result, &PathError{"readdir", file.name, Eshortstat}
}
dir, e := UnmarshalDir(d.buf[d.bufp : d.bufp+int(m)])
if e != nil {
- return nil, &PathError{"readdir", file.name, e}
+ return result, &PathError{"readdir", file.name, e}
}
var f FileInfo
fileInfoFromStat(&f, dir)
result = append(result, f)
d.bufp += int(m)
- count--
+ n--
}
- return result, nil
-}
-// Readdirnames returns an array of up to count file names residing in the
-// directory associated with file. A negative count will return all of them.
-// Readdir returns the array and an Error, if any.
-func (file *File) Readdirnames(count int) (names []string, err Error) {
- fi, e := file.Readdir(count)
-
- if e != nil {
- return []string{}, e
+ if n >= 0 && len(result) == 0 {
+ return result, EOF
}
+ return result, nil
+}
+// Readdirnames reads and returns a slice of names from the directory f.
+//
+// If n > 0, Readdirnames returns at most n names. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdirnames returns all the names from the directory in
+// a single slice. In this case, if Readdirnames succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdirnames returns the names read until that point and
+// a non-nil error.
+func (file *File) Readdirnames(n int) (names []string, err Error) {
+ fi, err := file.Readdir(n)
names = make([]string, len(fi))
- err = nil
-
for i := range fi {
names[i] = fi[i].Name
}
-
return
}
@@ -142,7 +158,7 @@ func pdir(b []byte, d *Dir) []byte {
return b
}
-// UnmarshalDir reads a 9P Stat message from a 9P protocol message strored in b,
+// UnmarshalDir reads a 9P Stat message from a 9P protocol message stored in b,
// returning the corresponding Dir struct.
func UnmarshalDir(b []byte) (d *Dir, err Error) {
n := uint16(0)
@@ -172,7 +188,7 @@ func UnmarshalDir(b []byte) (d *Dir, err Error) {
return d, nil
}
-// gqid reads the qid part of a 9P Stat message from a 9P protocol message strored in b,
+// gqid reads the qid part of a 9P Stat message from a 9P protocol message stored in b,
// returning the corresponding Qid struct and the remaining slice of b.
func gqid(b []byte) (Qid, []byte) {
var q Qid
@@ -190,25 +206,25 @@ func pqid(b []byte, q Qid) []byte {
return b
}
-// gbit8 reads a byte-sized numeric value from a 9P protocol message strored in b,
+// gbit8 reads a byte-sized numeric value from a 9P protocol message stored in b,
// returning the value and the remaining slice of b.
func gbit8(b []byte) (uint8, []byte) {
return uint8(b[0]), b[1:]
}
-// gbit16 reads a 16-bit numeric value from a 9P protocol message strored in b,
+// gbit16 reads a 16-bit numeric value from a 9P protocol message stored in b,
// returning the value and the remaining slice of b.
func gbit16(b []byte) (uint16, []byte) {
return uint16(b[0]) | uint16(b[1])<<8, b[2:]
}
-// gbit32 reads a 32-bit numeric value from a 9P protocol message strored in b,
+// gbit32 reads a 32-bit numeric value from a 9P protocol message stored in b,
// returning the value and the remaining slice of b.
func gbit32(b []byte) (uint32, []byte) {
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
}
-// gbit64 reads a 64-bit numeric value from a 9P protocol message strored in b,
+// gbit64 reads a 64-bit numeric value from a 9P protocol message stored in b,
// returning the value and the remaining slice of b.
func gbit64(b []byte) (uint64, []byte) {
lo, b := gbit32(b)
@@ -216,7 +232,7 @@ func gbit64(b []byte) (uint64, []byte) {
return uint64(hi)<<32 | uint64(lo), b
}
-// gstring reads a string from a 9P protocol message strored in b,
+// gstring reads a string from a 9P protocol message stored in b,
// returning the value as a Go string and the remaining slice of b.
func gstring(b []byte) (string, []byte) {
n, b := gbit16(b)
diff --git a/libgo/go/os/dir_unix.go b/libgo/go/os/dir_unix.go
index f5b82230d1b..7835ed52b55 100644
--- a/libgo/go/os/dir_unix.go
+++ b/libgo/go/os/dir_unix.go
@@ -12,30 +12,40 @@ const (
blockSize = 4096
)
-// Readdirnames reads the contents of the directory associated with file and
-// returns an array of up to count names, in directory order. Subsequent
-// calls on the same file will yield further names.
-// A negative count means to read until EOF.
-// Readdirnames returns the array and an Error, if any.
-func (file *File) Readdirnames(count int) (names []string, err Error) {
+// Readdirnames reads and returns a slice of names from the directory f.
+//
+// If n > 0, Readdirnames returns at most n names. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdirnames returns all the names from the directory in
+// a single slice. In this case, if Readdirnames succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdirnames returns the names read until that point and
+// a non-nil error.
+func (f *File) Readdirnames(n int) (names []string, err Error) {
// If this file has no dirinfo, create one.
- if file.dirinfo == nil {
- file.dirinfo = new(dirInfo)
+ if f.dirinfo == nil {
+ f.dirinfo = new(dirInfo)
// The buffer must be at least a block long.
- file.dirinfo.buf = make([]byte, blockSize)
+ f.dirinfo.buf = make([]byte, blockSize)
}
- d := file.dirinfo
- size := count
- if size < 0 {
+ d := f.dirinfo
+
+ size := n
+ if size <= 0 {
size = 100
+ n = -1
}
+
names = make([]string, 0, size) // Empty with room to grow.
- for count != 0 {
+ for n != 0 {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
d.bufp = 0
var errno int
- d.nbuf, errno = syscall.ReadDirent(file.fd, d.buf)
+ d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf)
if errno != 0 {
return names, NewSyscallError("readdirent", errno)
}
@@ -46,9 +56,12 @@ func (file *File) Readdirnames(count int) (names []string, err Error) {
// Drain the buffer
var nb, nc int
- nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], count, names)
+ nb, nc, names = syscall.ParseDirent(d.buf[d.bufp:d.nbuf], n, names)
d.bufp += nb
- count -= nc
+ n -= nc
+ }
+ if n >= 0 && len(names) == 0 {
+ return names, EOF
}
return names, nil
}
diff --git a/libgo/go/os/env_plan9.go b/libgo/go/os/env_plan9.go
index 14df55ed0ed..1fed89f9279 100644
--- a/libgo/go/os/env_plan9.go
+++ b/libgo/go/os/env_plan9.go
@@ -23,13 +23,18 @@ func Getenverror(key string) (value string, err Error) {
}
defer f.Close()
- var buf [4096]byte
- n, e := f.Read(buf[:len(buf)-1])
+ l, _ := f.Seek(0, 2)
+ f.Seek(0, 0)
+ buf := make([]byte, l)
+ n, e := f.Read(buf)
if iserror(e) {
return "", ENOENV
}
- buf[n] = 0
- return string(buf[0:n]), nil
+
+ if n > 0 && buf[n-1] == 0 {
+ buf = buf[:n-1]
+ }
+ return string(buf), nil
}
// Getenv retrieves the value of the environment variable named by the key.
@@ -52,7 +57,7 @@ func Setenv(key, value string) Error {
}
defer f.Close()
- _, e = f.Write(syscall.StringByteSlice(value))
+ _, e = f.Write([]byte(value))
return nil
}
diff --git a/libgo/go/os/env_unix.go b/libgo/go/os/env_unix.go
index 8aa71e83a0c..9cc0b03d877 100644
--- a/libgo/go/os/env_unix.go
+++ b/libgo/go/os/env_unix.go
@@ -16,7 +16,6 @@ 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 {
diff --git a/libgo/go/os/env_windows.go b/libgo/go/os/env_windows.go
index a45d79be32a..e6ddc4065fe 100644
--- a/libgo/go/os/env_windows.go
+++ b/libgo/go/os/env_windows.go
@@ -119,7 +119,7 @@ func init() {
if e != 0 {
return
}
- defer syscall.LocalFree(uint32(uintptr(unsafe.Pointer(argv))))
+ defer syscall.LocalFree(syscall.Handle(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
index 2c4516ca7da..b4511dd2f4d 100644
--- a/libgo/go/os/error.go
+++ b/libgo/go/os/error.go
@@ -9,20 +9,17 @@ type Error interface {
String() string
}
-// A helper type that can be embedded or wrapped to simplify satisfying
-// Error.
-type ErrorString string
+// // errorString is a helper type used by NewError.
+type errorString string
-func (e ErrorString) String() string { return string(e) }
-func (e ErrorString) Temporary() bool { return false }
-func (e ErrorString) Timeout() bool { return false }
+func (e errorString) String() string { return string(e) }
// Note: If the name of the function NewError changes,
// pkg/go/doc/doc.go should be adjusted since it hardwires
// this name in a heuristic.
-// NewError converts s to an ErrorString, which satisfies the Error interface.
-func NewError(s string) Error { return ErrorString(s) }
+// // NewError returns a new error with error.String() == s.
+func NewError(s string) Error { return errorString(s) }
// PathError records an error and the operation and file path that caused it.
type PathError struct {
diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go
index 3374775b8e7..cacfc150c43 100644
--- a/libgo/go/os/error_plan9.go
+++ b/libgo/go/os/error_plan9.go
@@ -45,6 +45,7 @@ var (
EEXIST = Eexist
EIO = Eio
EACCES = Eperm
+ EPERM = Eperm
EISDIR = syscall.EISDIR
ENAMETOOLONG = NewError("file name too long")
diff --git a/libgo/go/os/error_posix.go b/libgo/go/os/error_posix.go
index 0ee34e4b0ef..d43f1786d37 100644
--- a/libgo/go/os/error_posix.go
+++ b/libgo/go/os/error_posix.go
@@ -13,7 +13,7 @@ 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()
+ return e == Errno(syscall.EINTR) || e == Errno(syscall.EMFILE) || e.Timeout()
}
func (e Errno) Timeout() bool {
diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go
index f62caf9a069..33e223fd296 100644
--- a/libgo/go/os/exec.go
+++ b/libgo/go/os/exec.go
@@ -13,10 +13,11 @@ import (
type Process struct {
Pid int
handle int
+ done bool // process has been successfuly waited on
}
func newProcess(pid, handle int) *Process {
- p := &Process{pid, handle}
+ p := &Process{Pid: pid, handle: handle}
runtime.SetFinalizer(p, (*Process).Release)
return p
}
@@ -37,6 +38,17 @@ type ProcAttr struct {
// depending on the underlying operating system. A nil entry corresponds
// to that file being closed when the process starts.
Files []*File
+
+ // Operating system-specific process creation attributes.
+ // Note that setting this field means that your program
+ // may not execute properly or even compile on some
+ // operating systems.
+ Sys *syscall.SysProcAttr
+}
+
+// A Signal can represent any operating system signal.
+type Signal interface {
+ String() string
}
// Getpid returns the process id of the caller.
diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go
index 11874aba677..6f0722a222e 100644
--- a/libgo/go/os/exec_plan9.go
+++ b/libgo/go/os/exec_plan9.go
@@ -15,6 +15,7 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
+ Sys: attr.Sys,
}
// Create array of integer (system) fds.
@@ -37,6 +38,38 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
return newProcess(pid, h), nil
}
+// Plan9Note implements the Signal interface on Plan 9.
+type Plan9Note string
+
+func (note Plan9Note) String() string {
+ return string(note)
+}
+
+func (p *Process) Signal(sig Signal) Error {
+ if p.done {
+ return NewError("os: process already finished")
+ }
+
+ f, e := OpenFile("/proc/"+itoa(p.Pid)+"/note", O_WRONLY, 0)
+ if iserror(e) {
+ return NewSyscallError("signal", e)
+ }
+ defer f.Close()
+ _, e = f.Write([]byte(sig.String()))
+ return e
+}
+
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() Error {
+ f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
+ if iserror(e) {
+ return NewSyscallError("kill", e)
+ }
+ defer f.Close()
+ _, e = f.Write([]byte("kill"))
+ return e
+}
+
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
@@ -51,7 +84,9 @@ func Exec(name string, argv []string, envv []string) Error {
}
// Waitmsg stores the information about an exited process as reported by Wait.
-type Waitmsg syscall.Waitmsg
+type Waitmsg struct {
+ syscall.Waitmsg
+}
// Wait waits for the Process to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
@@ -71,11 +106,12 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
}
if waitmsg.Pid == p.Pid {
+ p.done = true
break
}
}
- return (*Waitmsg)(&waitmsg), nil
+ return &Waitmsg{waitmsg}, nil
}
// Wait waits for process pid to exit or stop, and then returns a
@@ -109,6 +145,9 @@ func FindProcess(pid int) (p *Process, err Error) {
return newProcess(pid, 0), nil
}
-func (w Waitmsg) String() string {
+func (w *Waitmsg) String() string {
+ if w == nil {
+ return "<nil>"
+ }
return "exit status: " + w.Msg
}
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index 9102dc0a4cb..f37bfab589a 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.go
@@ -4,28 +4,38 @@
package os
-import "syscall"
+import (
+ "runtime"
+ "syscall"
+)
+
+type UnixSignal int32
+
+func (sig UnixSignal) String() string {
+ s := runtime.Signame(int32(sig))
+ if len(s) > 0 {
+ return s
+ }
+ return "UnixSignal"
+}
// StartProcess starts a new process with the program, arguments and attributes
// specified by name, argv and attr.
+//
+// StartProcess is a low-level interface. The exec package provides
+// higher-level interfaces.
func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err Error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
+ Sys: attr.Sys,
}
if sysattr.Env == nil {
sysattr.Env = Environ()
}
- // Create array of integer (system) fds.
- intfd := make([]int, len(attr.Files))
- for i, f := range attr.Files {
- if f == nil {
- intfd[i] = -1
- } else {
- intfd[i] = f.Fd()
- }
+ for _, f := range attr.Files {
+ sysattr.Files = append(sysattr.Files, f.Fd())
}
- sysattr.Files = intfd
pid, h, e := syscall.StartProcess(name, argv, sysattr)
if iserror(e) {
@@ -34,10 +44,17 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
return newProcess(pid, h), nil
}
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() Error {
+ return p.Signal(SIGKILL)
+}
+
// 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.
-// StartProcess is almost always a better way to execute a program.
+//
+// To run a child process, see StartProcess (for a low-level interface)
+// or the exec package (for higher-level interfaces).
func Exec(name string, argv []string, envv []string) Error {
if envv == nil {
envv = Environ()
@@ -104,7 +121,10 @@ func itod(i int) string {
return string(b[bp:])
}
-func (w Waitmsg) String() string {
+func (w *Waitmsg) String() string {
+ if w == nil {
+ return "<nil>"
+ }
// TODO(austin) Use signal names when possible?
res := ""
switch {
diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go
index 8990d6a97ec..8a4b2e1b806 100644
--- a/libgo/go/os/exec_unix.go
+++ b/libgo/go/os/exec_unix.go
@@ -38,6 +38,9 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
if e != 0 {
return nil, NewSyscallError("wait", e)
}
+ if options&WSTOPPED == 0 {
+ p.done = true
+ }
w = new(Waitmsg)
w.Pid = pid1
w.WaitStatus = status
@@ -45,6 +48,17 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
return w, nil
}
+// Signal sends a signal to the Process.
+func (p *Process) Signal(sig Signal) Error {
+ if p.done {
+ return NewError("os: process already finished")
+ }
+ if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != 0 {
+ return Errno(e)
+ }
+ return nil
+}
+
// Release releases any resources associated with the Process.
func (p *Process) Release() Error {
// NOOP for unix.
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index ae8ffeab2e9..65e94ac4acc 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -10,28 +10,42 @@ import (
)
func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
- s, e := syscall.WaitForSingleObject(int32(p.handle), syscall.INFINITE)
+ s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
switch s {
case syscall.WAIT_OBJECT_0:
break
case syscall.WAIT_FAILED:
return nil, NewSyscallError("WaitForSingleObject", e)
default:
- return nil, ErrorString("os: unexpected result from WaitForSingleObject")
+ return nil, NewError("os: unexpected result from WaitForSingleObject")
}
var ec uint32
- e = syscall.GetExitCodeProcess(uint32(p.handle), &ec)
+ e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec)
if e != 0 {
return nil, NewSyscallError("GetExitCodeProcess", e)
}
+ p.done = true
return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
}
+// Signal sends a signal to the Process.
+func (p *Process) Signal(sig Signal) Error {
+ if p.done {
+ return NewError("os: process already finished")
+ }
+ switch sig.(UnixSignal) {
+ case SIGKILL:
+ e := syscall.TerminateProcess(syscall.Handle(p.handle), 1)
+ return NewSyscallError("TerminateProcess", e)
+ }
+ return Errno(syscall.EWINDOWS)
+}
+
func (p *Process) Release() Error {
if p.handle == -1 {
return EINVAL
}
- e := syscall.CloseHandle(int32(p.handle))
+ e := syscall.CloseHandle(syscall.Handle(p.handle))
if e != 0 {
return NewSyscallError("CloseHandle", e)
}
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index dff8fa862ce..4335d45e5a0 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -4,39 +4,17 @@
// Package os provides a platform-independent interface to operating system
// functionality. The design is Unix-like.
+// The os interface is intended to be uniform across all operating systems.
+// Features not generally available appear in the system-specific package syscall.
package os
import (
- "runtime"
- "sync"
"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
- l sync.Mutex // used to implement windows pread/pwrite
-}
-
-// 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: fd, name: name}
- 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 (
@@ -185,9 +163,7 @@ 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)
+ return file.Write([]byte(s))
}
// Mkdir creates a new directory with the specified name and permission bits.
diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go
index 7b473f80221..1e94fb715b9 100644
--- a/libgo/go/os/file_plan9.go
+++ b/libgo/go/os/file_plan9.go
@@ -9,6 +9,31 @@ import (
"syscall"
)
+// File represents an open file descriptor.
+type File struct {
+ fd int
+ name string
+ dirinfo *dirInfo // nil unless directory being read
+}
+
+// Fd returns the integer Unix file descriptor referencing the open file.
+func (file *File) Fd() int {
+ if file == nil {
+ return -1
+ }
+ return file.fd
+}
+
+// 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: fd, name: name}
+ runtime.SetFinalizer(f, (*File).Close)
+ return f
+}
+
// Auxiliary information if the File describes a directory
type dirInfo struct {
buf [syscall.STATMAX]byte // buffer for directory I/O
@@ -19,7 +44,6 @@ type dirInfo struct {
func epipecheck(file *File, e syscall.Error) {
}
-
// 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"
@@ -30,14 +54,43 @@ const DevNull = "/dev/null"
// methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
- var fd int
- var e syscall.Error
+ var (
+ fd int
+ e syscall.Error
+ create bool
+ excl bool
+ trunc bool
+ append bool
+ )
- syscall.ForkLock.RLock()
if flag&O_CREATE == O_CREATE {
- fd, e = syscall.Create(name, flag & ^O_CREATE, perm)
+ flag = flag & ^O_CREATE
+ create = true
+ }
+ if flag&O_EXCL == O_EXCL {
+ excl = true
+ }
+ if flag&O_TRUNC == O_TRUNC {
+ trunc = true
+ }
+ // O_APPEND is emulated on Plan 9
+ if flag&O_APPEND == O_APPEND {
+ flag = flag &^ O_APPEND
+ append = true
+ }
+
+ syscall.ForkLock.RLock()
+ if (create && trunc) || excl {
+ fd, e = syscall.Create(name, flag, perm)
} else {
fd, e = syscall.Open(name, flag)
+ if e != nil && create {
+ var e1 syscall.Error
+ fd, e1 = syscall.Create(name, flag, perm)
+ if e1 == nil {
+ e = nil
+ }
+ }
}
syscall.ForkLock.RUnlock()
@@ -45,6 +98,12 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
return nil, &PathError{"open", name, e}
}
+ if append {
+ if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil {
+ return nil, &PathError{"seek", name, e}
+ }
+ }
+
return NewFile(fd, name), nil
}
@@ -69,8 +128,12 @@ func (file *File) Close() Error {
// Stat returns the FileInfo structure describing file.
// It returns the FileInfo and an error, if any.
-func (file *File) Stat() (fi *FileInfo, err Error) {
- return dirstat(file)
+func (f *File) Stat() (fi *FileInfo, err Error) {
+ d, err := dirstat(f)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
}
// Truncate changes the size of the file.
@@ -90,10 +153,15 @@ func (f *File) Truncate(size int64) Error {
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
var d Dir
- d.Null()
+ var mask = ^uint32(0777)
- d.Mode = mode & 0777
+ d.Null()
+ odir, e := dirstat(f)
+ if iserror(e) {
+ return &PathError{"chmod", f.name, e}
+ }
+ d.Mode = (odir.Mode & mask) | (mode &^ mask)
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", f.name, e}
}
@@ -188,26 +256,17 @@ func Rename(oldname, newname string) Error {
// Chmod changes the mode of the named file to mode.
func Chmod(name string, mode uint32) Error {
var d Dir
- d.Null()
-
- d.Mode = mode & 0777
+ var mask = ^uint32(0777)
- if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ d.Null()
+ odir, e := dirstat(name)
+ if iserror(e) {
return &PathError{"chmod", name, e}
}
- return nil
-}
-
-// ChownPlan9 changes the uid and gid strings of the named file.
-func ChownPlan9(name, uid, gid string) Error {
- var d Dir
- d.Null()
-
- d.Uid = uid
- d.Gid = gid
+ d.Mode = (odir.Mode & mask) | (mode &^ mask)
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
- return &PathError{"chown_plan9", name, e}
+ return &PathError{"chmod", name, e}
}
return nil
}
@@ -244,7 +303,6 @@ func Pipe() (r *File, w *File, err Error) {
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
-
// not supported on Plan 9
// Link creates a hard link.
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index f1191d61feb..0791a0dc04b 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The os package provides a platform-independent interface to operating
-// system functionality. The design is Unix-like.
package os
import (
@@ -23,26 +21,6 @@ func epipecheck(file *File, e int) {
}
}
-
-// 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 iserror(e) {
- 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
-}
-
// 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.
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index 4c69cc83802..8243701ad24 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -9,6 +9,32 @@ import (
"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 {
+ if file == nil {
+ return -1
+ }
+ return file.fd
+}
+
+// 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: fd, name: name}
+ runtime.SetFinalizer(f, (*File).Close)
+ return f
+}
+
// Auxiliary information if the File describes a directory
type dirInfo struct {
buf []byte // buffer for directory I/O
@@ -75,21 +101,27 @@ func (file *File) Stat() (fi *FileInfo, err Error) {
}
// 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
+// returns an array of up to n FileInfo structures, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
// further FileInfos.
-// 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) {
+//
+// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
+// Readdir returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is os.EOF.
+//
+// If n <= 0, Readdir returns all the FileInfo from the directory in
+// a single slice. In this case, if Readdir succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil os.Error. If it encounters an error before the end of the
+// directory, Readdir returns the FileInfo read until that point
+// and a non-nil error.
+func (file *File) Readdir(n int) (fi []FileInfo, err Error) {
dirname := file.name
if dirname == "" {
dirname = "."
}
dirname += "/"
- names, err1 := file.Readdirnames(count)
- if err1 != nil {
- return nil, err1
- }
+ names, err := file.Readdirnames(n)
fi = make([]FileInfo, len(names))
for i, filename := range names {
fip, err := Lstat(dirname + filename)
@@ -161,3 +193,22 @@ func basename(name string) string {
return name
}
+
+// 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 iserror(e) {
+ 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
+}
diff --git a/libgo/go/os/inotify/inotify_linux.go b/libgo/go/os/inotify/inotify_linux.go
index 7c7b7698feb..99fa5162223 100644
--- a/libgo/go/os/inotify/inotify_linux.go
+++ b/libgo/go/os/inotify/inotify_linux.go
@@ -34,7 +34,6 @@ import (
"unsafe"
)
-
type Event struct {
Mask uint32 // Mask of events
Cookie uint32 // Unique cookie associating related events (for rename(2))
@@ -56,7 +55,6 @@ type Watcher struct {
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()
@@ -76,7 +74,6 @@ func NewWatcher() (*Watcher, os.Error) {
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
@@ -119,13 +116,11 @@ func (w *Watcher) AddWatch(path string, flags uint32) os.Error {
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]
@@ -140,7 +135,6 @@ func (w *Watcher) RemoveWatch(path string) os.Error {
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() {
@@ -208,7 +202,6 @@ func (w *Watcher) readEvents() {
}
}
-
// String formats the event e in the form
// "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
func (e *Event) String() string {
diff --git a/libgo/go/os/inotify/inotify_linux_test.go b/libgo/go/os/inotify/inotify_linux_test.go
index e29a46d6c2d..aa72604eb92 100644
--- a/libgo/go/os/inotify/inotify_linux_test.go
+++ b/libgo/go/os/inotify/inotify_linux_test.go
@@ -74,7 +74,6 @@ func TestInotifyEvents(t *testing.T) {
}
}
-
func TestInotifyClose(t *testing.T) {
watcher, _ := NewWatcher()
watcher.Close()
diff --git a/libgo/go/os/signal/mkunix.sh b/libgo/go/os/mkunixsignals.sh
index ec5c9d6808e..3487bc3bc3c 100644
--- a/libgo/go/os/signal/mkunix.sh
+++ b/libgo/go/os/mkunixsignals.sh
@@ -8,13 +8,13 @@ echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
echo
cat <<EOH
-package signal
+package os
import (
"syscall"
)
-var _ = syscall.Syscall // in case there are zero signals
+var _ = syscall.Open // in case there are zero signals
const (
EOH
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 8df69626113..3f7d3063106 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -234,11 +234,14 @@ func smallReaddirnames(file *File, length int, t *testing.T) []string {
count := 0
for {
d, err := file.Readdirnames(1)
+ if err == EOF {
+ break
+ }
if err != nil {
- t.Fatalf("readdir %q failed: %v", file.Name(), err)
+ t.Fatalf("readdirnames %q failed: %v", file.Name(), err)
}
if len(d) == 0 {
- break
+ t.Fatalf("readdirnames %q returned empty slice and no error", file.Name())
}
names[count] = d[0]
count++
@@ -281,9 +284,81 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
}
}
+func TestReaddirNValues(t *testing.T) {
+ if testing.Short() {
+ t.Logf("test.short; skipping")
+ return
+ }
+ dir, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("TempDir: %v", err)
+ }
+ defer RemoveAll(dir)
+ for i := 1; i <= 105; i++ {
+ f, err := Create(filepath.Join(dir, fmt.Sprintf("%d", i)))
+ if err != nil {
+ t.Fatalf("Create: %v", err)
+ }
+ f.Write([]byte(strings.Repeat("X", i)))
+ f.Close()
+ }
+
+ var d *File
+ openDir := func() {
+ var err Error
+ d, err = Open(dir)
+ if err != nil {
+ t.Fatalf("Open directory: %v", err)
+ }
+ }
+
+ readDirExpect := func(n, want int, wantErr Error) {
+ fi, err := d.Readdir(n)
+ if err != wantErr {
+ t.Fatalf("Readdir of %d got error %v, want %v", n, err, wantErr)
+ }
+ if g, e := len(fi), want; g != e {
+ t.Errorf("Readdir of %d got %d files, want %d", n, g, e)
+ }
+ }
+
+ readDirNamesExpect := func(n, want int, wantErr Error) {
+ fi, err := d.Readdirnames(n)
+ if err != wantErr {
+ t.Fatalf("Readdirnames of %d got error %v, want %v", n, err, wantErr)
+ }
+ if g, e := len(fi), want; g != e {
+ t.Errorf("Readdirnames of %d got %d files, want %d", n, g, e)
+ }
+ }
+
+ for _, fn := range []func(int, int, Error){readDirExpect, readDirNamesExpect} {
+ // Test the slurp case
+ openDir()
+ fn(0, 105, nil)
+ fn(0, 0, nil)
+ d.Close()
+
+ // Slurp with -1 instead
+ openDir()
+ fn(-1, 105, nil)
+ fn(-2, 0, nil)
+ fn(0, 0, nil)
+ d.Close()
+
+ // Test the bounded case
+ openDir()
+ fn(1, 1, nil)
+ fn(2, 2, nil)
+ fn(105, 102, nil) // and tests buffer >100 case
+ fn(3, 0, EOF)
+ d.Close()
+ }
+}
+
func TestHardLink(t *testing.T) {
- // Hardlinks are not supported under windows.
- if syscall.OS == "windows" {
+ // Hardlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
from, to := "hardlinktestfrom", "hardlinktestto"
@@ -315,8 +390,8 @@ func TestHardLink(t *testing.T) {
}
func TestSymLink(t *testing.T) {
- // Symlinks are not supported under windows.
- if syscall.OS == "windows" {
+ // Symlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
from, to := "symlinktestfrom", "symlinktestto"
@@ -377,8 +452,8 @@ func TestSymLink(t *testing.T) {
}
func TestLongSymlink(t *testing.T) {
- // Symlinks are not supported under windows.
- if syscall.OS == "windows" {
+ // Symlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
s := "0123456789abcdef"
@@ -511,8 +586,9 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
}
func TestChown(t *testing.T) {
- // Chown is not supported under windows.
- if syscall.OS == "windows" {
+ // Chown is not supported under windows or Plan 9.
+ // Plan9 provides a native ChownPlan9 version instead.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
// Use TempDir() to make sure we're on a local file system,
@@ -631,7 +707,11 @@ func TestChtimes(t *testing.T) {
t.Fatalf("second Stat %s: %s", f.Name(), err)
}
- if postStat.Atime_ns >= preStat.Atime_ns {
+ /* Plan 9:
+ Mtime is the time of the last change of content. Similarly, atime is set whenever the
+ contents are accessed; also, it is set whenever mtime is set.
+ */
+ if postStat.Atime_ns >= preStat.Atime_ns && syscall.OS != "plan9" {
t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
preStat.Atime_ns,
postStat.Atime_ns)
@@ -656,6 +736,10 @@ func TestChdirAndGetwd(t *testing.T) {
// These are chosen carefully not to be symlinks on a Mac
// (unlike, say, /var, /etc, and /tmp).
dirs := []string{"/", "/usr/bin"}
+ // /usr/bin does not usually exist on Plan 9.
+ if syscall.OS == "plan9" {
+ dirs = []string{"/", "/usr"}
+ }
for mode := 0; mode < 2; mode++ {
for _, d := range dirs {
if mode == 0 {
@@ -781,7 +865,15 @@ func TestOpenError(t *testing.T) {
t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
}
if perr.Error != tt.error {
- t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
+ if syscall.OS == "plan9" {
+ syscallErrStr := perr.Error.String()
+ expectedErrStr := strings.Replace(tt.error.String(), "file ", "", 1)
+ if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
+ t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
+ }
+ } else {
+ t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
+ }
}
}
}
@@ -801,7 +893,14 @@ func run(t *testing.T, cmd []string) string {
var b bytes.Buffer
io.Copy(&b, r)
- p.Wait(0)
+ _, err = p.Wait(0)
+ if err != nil {
+ t.Fatalf("run hostname Wait: %v", err)
+ }
+ err = p.Kill()
+ if err == nil {
+ t.Errorf("expected an error from Kill running 'hostname'")
+ }
output := b.String()
if n := len(output); n > 0 && output[n-1] == '\n' {
output = output[0 : n-1]
@@ -813,10 +912,10 @@ func run(t *testing.T, cmd []string) string {
return output
}
-
func TestHostname(t *testing.T) {
// There is no other way to fetch hostname on windows, but via winapi.
- if syscall.OS == "windows" {
+ // On Plan 9 it is can be taken from #c/sysname as Hostname() does.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
// Check internal Hostname() against the output of /bin/hostname.
@@ -913,7 +1012,15 @@ func TestAppend(t *testing.T) {
}
s = writeFile(t, f, O_CREATE|O_APPEND|O_RDWR, "new&append")
if s != "new&append" {
- t.Fatalf("writeFile: have %q want %q", s, "new&append")
+ t.Fatalf("writeFile: after append have %q want %q", s, "new&append")
+ }
+ s = writeFile(t, f, O_CREATE|O_RDWR, "old")
+ if s != "old&append" {
+ t.Fatalf("writeFile: after create have %q want %q", s, "old&append")
+ }
+ s = writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
+ if s != "new" {
+ t.Fatalf("writeFile: after truncate have %q want %q", s, "new")
}
}
@@ -939,3 +1046,11 @@ func TestStatDirWithTrailingSlash(t *testing.T) {
t.Fatal("stat failed:", err)
}
}
+
+func TestNilWaitmsgString(t *testing.T) {
+ var w *Waitmsg
+ s := w.String()
+ if s != "<nil>" {
+ t.Errorf("(*Waitmsg)(nil).String() = %q, want %q", s, "<nil>")
+ }
+}
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
index 0eb3ee50369..a8dfce30752 100644
--- a/libgo/go/os/path.go
+++ b/libgo/go/os/path.go
@@ -4,7 +4,6 @@
package os
-
// MkdirAll creates a directory named path,
// along with any necessary parents, and returns nil,
// or else returns an error.
@@ -24,12 +23,12 @@ func MkdirAll(path string, perm uint32) Error {
// Doesn't already exist; make sure parent does.
i := len(path)
- for i > 0 && path[i-1] == '/' { // Skip trailing slashes.
+ for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
i--
}
j := i
- for j > 0 && path[j-1] != '/' { // Scan backward over element.
+ for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element.
j--
}
@@ -90,11 +89,14 @@ func RemoveAll(path string) Error {
for {
names, err1 := fd.Readdirnames(100)
for _, name := range names {
- err1 := RemoveAll(path + "/" + name)
+ err1 := RemoveAll(path + string(PathSeparator) + name)
if err == nil {
err = err1
}
}
+ if err1 == EOF {
+ break
+ }
// If Readdirnames returned an error, use it.
if err == nil {
err = err1
diff --git a/libgo/go/os/path_plan9.go b/libgo/go/os/path_plan9.go
new file mode 100644
index 00000000000..3121b7bc712
--- /dev/null
+++ b/libgo/go/os/path_plan9.go
@@ -0,0 +1,15 @@
+// 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
+
+const (
+ PathSeparator = '/' // OS-specific path separator
+ PathListSeparator = 0 // OS-specific path list separator
+)
+
+// IsPathSeparator returns true if c is a directory separator character.
+func IsPathSeparator(c uint8) bool {
+ return PathSeparator == c
+}
diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go
index 483bb639535..31acbaa4356 100644
--- a/libgo/go/os/path_test.go
+++ b/libgo/go/os/path_test.go
@@ -6,6 +6,7 @@ package os_test
import (
. "os"
+ "path/filepath"
"testing"
"runtime"
"syscall"
@@ -29,10 +30,11 @@ func TestMkdirAll(t *testing.T) {
// Make file.
fpath := path + "/file"
- _, err = Create(fpath)
+ f, err := Create(fpath)
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
+ defer f.Close()
// Can't make directory named after file.
err = MkdirAll(fpath, 0777)
@@ -43,8 +45,8 @@ func TestMkdirAll(t *testing.T) {
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)
+ if filepath.Clean(perr.Path) != filepath.Clean(fpath) {
+ t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, filepath.Clean(perr.Path), filepath.Clean(fpath))
}
// Can't make subdirectory of file.
@@ -57,8 +59,16 @@ func TestMkdirAll(t *testing.T) {
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)
+ if filepath.Clean(perr.Path) != filepath.Clean(fpath) {
+ t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, filepath.Clean(perr.Path), filepath.Clean(fpath))
+ }
+
+ if syscall.OS == "windows" {
+ path := `_test\_TestMkdirAll_\dir\.\dir2\`
+ err := MkdirAll(path, 0777)
+ if err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
}
}
@@ -156,8 +166,8 @@ func TestRemoveAll(t *testing.T) {
}
func TestMkdirAllWithSymlink(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Log("Skipping test: symlinks don't exist under Windows")
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ t.Log("Skipping test: symlinks don't exist under Windows/Plan 9")
return
}
@@ -181,7 +191,7 @@ func TestMkdirAllWithSymlink(t *testing.T) {
}
func TestMkdirAllAtSlash(t *testing.T) {
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
RemoveAll("/_go_os_test")
diff --git a/libgo/go/os/path_unix.go b/libgo/go/os/path_unix.go
new file mode 100644
index 00000000000..0d327cddd3e
--- /dev/null
+++ b/libgo/go/os/path_unix.go
@@ -0,0 +1,15 @@
+// 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
+
+const (
+ PathSeparator = '/' // OS-specific path separator
+ PathListSeparator = ':' // OS-specific path list separator
+)
+
+// IsPathSeparator returns true if c is a directory separator character.
+func IsPathSeparator(c uint8) bool {
+ return PathSeparator == c
+}
diff --git a/libgo/go/os/path_windows.go b/libgo/go/os/path_windows.go
new file mode 100644
index 00000000000..61f2ca59ff4
--- /dev/null
+++ b/libgo/go/os/path_windows.go
@@ -0,0 +1,16 @@
+// 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
+
+const (
+ PathSeparator = '\\' // OS-specific path separator
+ PathListSeparator = ';' // OS-specific path list separator
+)
+
+// IsPathSeparator returns true if c is a directory separator character.
+func IsPathSeparator(c uint8) bool {
+ // NOTE: Windows accept / as path separator.
+ return c == '\\' || c == '/'
+}
diff --git a/libgo/go/os/proc.go b/libgo/go/os/proc.go
index 481ef603371..dfe388f2502 100644
--- a/libgo/go/os/proc.go
+++ b/libgo/go/os/proc.go
@@ -11,7 +11,6 @@ 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() }
diff --git a/libgo/go/os/signal/signal.go b/libgo/go/os/signal/signal.go
index 666c03e73c4..520f3f8a9ea 100644
--- a/libgo/go/os/signal/signal.go
+++ b/libgo/go/os/signal/signal.go
@@ -6,35 +6,20 @@
package signal
import (
+ "os"
"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
+var Incoming <-chan os.Signal
-func process(ch chan<- Signal) {
+func process(ch chan<- os.Signal) {
for {
var mask uint32 = runtime.Sigrecv()
for sig := uint(0); sig < 32; sig++ {
if mask&(1<<sig) != 0 {
- ch <- UnixSignal(sig)
+ ch <- os.UnixSignal(sig)
}
}
}
@@ -42,7 +27,7 @@ func process(ch chan<- Signal) {
func init() {
runtime.Siginit()
- ch := make(chan Signal) // Done here so Incoming can have type <-chan Signal
+ ch := make(chan os.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
index f2679f14dc6..00eb29578f9 100644
--- a/libgo/go/os/signal/signal_test.go
+++ b/libgo/go/os/signal/signal_test.go
@@ -5,6 +5,7 @@
package signal
import (
+ "os"
"syscall"
"testing"
)
@@ -13,7 +14,7 @@ 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)
+ if sig := (<-Incoming).(os.UnixSignal); sig != os.SIGHUP {
+ t.Errorf("signal was %v, want %v", sig, os.SIGHUP)
}
}
diff --git a/libgo/go/os/stat_openbsd.go b/libgo/go/os/stat_openbsd.go
new file mode 100644
index 00000000000..6d3a3813b09
--- /dev/null
+++ b/libgo/go/os/stat_openbsd.go
@@ -0,0 +1,32 @@
+// Copyright 2009 The Go Authors. 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 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 = stat.Blocks
+ fi.Atime_ns = syscall.TimespecToNsec(stat.Atim)
+ fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtim)
+ fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctim)
+ fi.Name = basename(name)
+ if isSymlink(lstat) && !isSymlink(stat) {
+ fi.FollowedSymlink = true
+ }
+ return fi
+}
diff --git a/libgo/go/os/stat_plan9.go b/libgo/go/os/stat_plan9.go
index e96749d33f3..173a23f8bde 100644
--- a/libgo/go/os/stat_plan9.go
+++ b/libgo/go/os/stat_plan9.go
@@ -26,7 +26,7 @@ func fileInfoFromStat(fi *FileInfo, d *Dir) *FileInfo {
}
// arg is an open *File or a path string.
-func dirstat(arg interface{}) (fi *FileInfo, err Error) {
+func dirstat(arg interface{}) (d *Dir, err Error) {
var name string
nd := syscall.STATFIXLEN + 16*4
@@ -62,23 +62,29 @@ func dirstat(arg interface{}) (fi *FileInfo, err Error) {
if e != nil {
return nil, &PathError{"stat", name, e}
}
-
- return fileInfoFromStat(new(FileInfo), d), nil
+ return d, e
}
}
return nil, &PathError{"stat", name, Ebadstat}
}
-
// Stat returns a FileInfo structure describing the named file and an error, if any.
func Stat(name string) (fi *FileInfo, err Error) {
- return dirstat(name)
+ d, err := dirstat(name)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link (though Plan 9 does not have symbolic links),
// the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
- return dirstat(name)
+ d, err := dirstat(name)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
}
diff --git a/libgo/go/os/str.go b/libgo/go/os/str.go
new file mode 100644
index 00000000000..8dc9e4747df
--- /dev/null
+++ b/libgo/go/os/str.go
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+func itoa(val int) string { // do it here rather than with fmt to avoid dependency
+ if val < 0 {
+ return "-" + itoa(-val)
+ }
+ var buf [32]byte // big enough for int64
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return string(buf[i:])
+}
diff --git a/libgo/go/os/sys_linux.go b/libgo/go/os/sys_linux.go
index 408d667c7cf..2accd6c1f0d 100644
--- a/libgo/go/os/sys_linux.go
+++ b/libgo/go/os/sys_linux.go
@@ -6,7 +6,6 @@
package os
-
// Hostname returns the host name reported by the kernel.
func Hostname() (name string, err Error) {
f, err := Open("/proc/sys/kernel/hostname")
diff --git a/libgo/go/os/sys_plan9.go b/libgo/go/os/sys_plan9.go
index f6af28b6116..c24cde05ec0 100644
--- a/libgo/go/os/sys_plan9.go
+++ b/libgo/go/os/sys_plan9.go
@@ -6,7 +6,6 @@
package os
-
func Hostname() (name string, err Error) {
f, err := Open("#c/sysname")
if err != nil {
diff --git a/libgo/go/os/time.go b/libgo/go/os/time.go
index 8e87a49e162..949574d19a0 100644
--- a/libgo/go/os/time.go
+++ b/libgo/go/os/time.go
@@ -6,7 +6,6 @@ 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
diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go
index 79f6e9d4976..df57b59a388 100644
--- a/libgo/go/os/types.go
+++ b/libgo/go/os/types.go
@@ -27,7 +27,7 @@ type FileInfo struct {
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.
+ Name string // base name of the file name provided in Open, Stat, etc.
FollowedSymlink bool // followed a symlink to get this information
}
diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go
index 7060530154a..0f04012c02f 100644
--- a/libgo/go/os/user/lookup_unix.go
+++ b/libgo/go/os/user/lookup_unix.go
@@ -27,6 +27,10 @@ static int mygetpwuid_r(int uid, struct passwd *pwd,
func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int __asm__ ("getpwnam_r")
func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int __asm__ ("getpwuid_r")
+func init() {
+ implemented = true
+}
+
// Lookup looks up a user by username. If the user cannot be found,
// the returned error is of type UnknownUserError.
func Lookup(username string) (*User, os.Error) {
diff --git a/libgo/go/os/user/user.go b/libgo/go/os/user/user.go
index dd009211d76..f71e11d8b21 100644
--- a/libgo/go/os/user/user.go
+++ b/libgo/go/os/user/user.go
@@ -9,6 +9,8 @@ import (
"strconv"
)
+var implemented = false // set to true by lookup_unix.go's init
+
// User represents a user account.
type User struct {
Uid int // user id
diff --git a/libgo/go/os/user/user_test.go b/libgo/go/os/user/user_test.go
index 2c142bf1817..59f15e4c675 100644
--- a/libgo/go/os/user/user_test.go
+++ b/libgo/go/os/user/user_test.go
@@ -13,8 +13,8 @@ import (
)
func skip(t *testing.T) bool {
- if runtime.GOARCH == "arm" {
- t.Logf("user: cgo not implemented on arm; skipping tests")
+ if !implemented {
+ t.Logf("user: not implemented; skipping tests")
return true
}
@@ -42,7 +42,7 @@ func TestLookup(t *testing.T) {
}
fi, err := os.Stat(u.HomeDir)
if err != nil || !fi.IsDirectory() {
- t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDirectory=%v", err, fi.IsDirectory())
+ t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDirectory=%v", u.HomeDir, err, fi.IsDirectory())
}
if u.Username == "" {
t.Fatalf("didn't get a username")
@@ -56,6 +56,6 @@ func TestLookup(t *testing.T) {
if !reflect.DeepEqual(u, un) {
t.Errorf("Lookup by userid vs. name didn't match\n"+
"LookupId(%d): %#v\n"+
- "Lookup(%q): %#v\n",uid, u, u.Username, un)
+ "Lookup(%q): %#v\n", uid, u, u.Username, un)
}
}
diff --git a/libgo/go/patch/patch.go b/libgo/go/patch/patch.go
index d4977dc9902..fcc8307e09c 100644
--- a/libgo/go/patch/patch.go
+++ b/libgo/go/patch/patch.go
@@ -319,4 +319,4 @@ func hasPrefix(s []byte, t string) bool {
// 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) }
+func splitLines(s []byte) [][]byte { return bytes.SplitAfter(s, newline) }
diff --git a/libgo/go/patch/textdiff.go b/libgo/go/patch/textdiff.go
index c7e693fc669..482bd678163 100644
--- a/libgo/go/patch/textdiff.go
+++ b/libgo/go/patch/textdiff.go
@@ -17,6 +17,8 @@ type TextChunk struct {
}
func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
+ var chunkHeader []byte
+
// Copy raw so it is safe to keep references to slices.
_, chunks := sections(raw, "@@ -")
delta := 0
@@ -26,13 +28,12 @@ func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
// Parse start line: @@ -oldLine,oldCount +newLine,newCount @@ junk
chunk := splitLines(raw)
- chunkHeader := chunk[0]
+ chunkHeader = chunk[0]
var ok bool
var oldLine, oldCount, newLine, newCount int
s := chunkHeader
if oldLine, s, ok = atoi(s, "@@ -", 10); !ok {
- ErrChunkHdr:
- return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
+ goto ErrChunkHdr
}
if len(s) == 0 || s[0] != ',' {
oldCount = 1
@@ -145,6 +146,9 @@ func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
}
}
return diff, nil
+
+ErrChunkHdr:
+ return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
}
var ErrPatchFailure = os.NewError("patch did not apply cleanly")
diff --git a/libgo/go/path/filepath/match.go b/libgo/go/path/filepath/match.go
index a05bb5f7e71..7fcc214c058 100644
--- a/libgo/go/path/filepath/match.go
+++ b/libgo/go/path/filepath/match.go
@@ -124,9 +124,8 @@ func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
s = s[n:]
chunk = chunk[1:]
// possibly negated
- notNegated := true
- if len(chunk) > 0 && chunk[0] == '^' {
- notNegated = false
+ negated := chunk[0] == '^'
+ if negated {
chunk = chunk[1:]
}
// parse all ranges
@@ -152,7 +151,7 @@ func matchChunk(chunk, s string) (rest string, ok bool, err os.Error) {
}
nrange++
}
- if match != notNegated {
+ if match == negated {
return
}
@@ -273,7 +272,7 @@ func glob(dir, pattern string, matches []string) (m []string, e os.Error) {
if err != nil {
return
}
- sort.SortStrings(names)
+ sort.Strings(names)
for _, n := range names {
matched, err := Match(pattern, n)
diff --git a/libgo/go/path/filepath/match_test.go b/libgo/go/path/filepath/match_test.go
index 0b594fa66e2..5fc7b9ca6e6 100644
--- a/libgo/go/path/filepath/match_test.go
+++ b/libgo/go/path/filepath/match_test.go
@@ -69,6 +69,13 @@ var matchTests = []MatchTest{
{"*x", "xxx", true, nil},
}
+func errp(e os.Error) string {
+ if e == nil {
+ return "<nil>"
+ }
+ return e.String()
+}
+
func TestMatch(t *testing.T) {
if runtime.GOOS == "windows" {
// XXX: Don't pass for windows.
@@ -77,7 +84,7 @@ 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)
+ t.Errorf("Match(%#q, %#q) = %v, %q want %v, %q", tt.pattern, tt.s, ok, errp(err), tt.match, errp(tt.err))
}
}
}
diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go
index 541a233066a..3d5b915c101 100644
--- a/libgo/go/path/filepath/path.go
+++ b/libgo/go/path/filepath/path.go
@@ -9,13 +9,14 @@ package filepath
import (
"bytes"
"os"
+ "runtime"
"sort"
"strings"
)
const (
- SeparatorString = string(Separator)
- ListSeparatorString = string(ListSeparator)
+ Separator = os.PathSeparator
+ ListSeparator = os.PathListSeparator
)
// Clean returns the shortest path name equivalent to path
@@ -37,19 +38,19 @@ const (
// Getting Dot-Dot right,''
// http://plan9.bell-labs.com/sys/doc/lexnames.html
func Clean(path string) string {
+ vol := VolumeName(path)
+ path = path[len(vol):]
if path == "" {
- return "."
+ return vol + "."
}
- rooted := IsAbs(path)
+ rooted := os.IsPathSeparator(path[0])
// 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.
- prefix := volumeName(path)
- path = path[len(prefix):]
n := len(path)
buf := []byte(path)
r, w, dotdot := 0, 0, 0
@@ -60,20 +61,20 @@ func Clean(path string) string {
for r < n {
switch {
- case isSeparator(path[r]):
+ case os.IsPathSeparator(path[r]):
// empty path element
r++
- case path[r] == '.' && (r+1 == n || isSeparator(path[r+1])):
+ case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
// . element
r++
- case path[r] == '.' && path[r+1] == '.' && (r+2 == n || isSeparator(path[r+2])):
+ case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
// .. element: remove to last separator
r += 2
switch {
case w > dotdot:
// can backtrack
w--
- for w > dotdot && !isSeparator(buf[w]) {
+ for w > dotdot && !os.IsPathSeparator(buf[w]) {
w--
}
case !rooted:
@@ -96,7 +97,7 @@ func Clean(path string) string {
w++
}
// copy element
- for ; r < n && !isSeparator(path[r]); r++ {
+ for ; r < n && !os.IsPathSeparator(path[r]); r++ {
buf[w] = path[r]
w++
}
@@ -109,7 +110,7 @@ func Clean(path string) string {
w++
}
- return prefix + string(buf[0:w])
+ return FromSlash(vol + string(buf[0:w]))
}
// ToSlash returns the result of replacing each separator character
@@ -118,7 +119,7 @@ func ToSlash(path string) string {
if Separator == '/' {
return path
}
- return strings.Replace(path, SeparatorString, "/", -1)
+ return strings.Replace(path, string(Separator), "/", -1)
}
// FromSlash returns the result of replacing each slash ('/') character
@@ -127,7 +128,7 @@ func FromSlash(path string) string {
if Separator == '/' {
return path
}
- return strings.Replace(path, "/", SeparatorString, -1)
+ return strings.Replace(path, "/", string(Separator), -1)
}
// SplitList splits a list of paths joined by the OS-specific ListSeparator.
@@ -135,16 +136,16 @@ func SplitList(path string) []string {
if path == "" {
return []string{}
}
- return strings.Split(path, ListSeparatorString, -1)
+ return strings.Split(path, string(ListSeparator))
}
// Split splits path immediately following the final Separator,
-// partitioning it into a directory and a file name components.
-// If there are no separators in path, Split returns an empty base
+// 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 := len(path) - 1
- for i >= 0 && !isSeparator(path[i]) {
+ for i >= 0 && !os.IsPathSeparator(path[i]) {
i--
}
return path[:i+1], path[i+1:]
@@ -155,7 +156,7 @@ func Split(path string) (dir, file string) {
func Join(elem ...string) string {
for i, e := range elem {
if e != "" {
- return Clean(strings.Join(elem[i:], SeparatorString))
+ return Clean(strings.Join(elem[i:], string(Separator)))
}
}
return ""
@@ -166,7 +167,7 @@ func Join(elem ...string) string {
// in the final element of path; it is empty if there is
// no dot.
func Ext(path string) string {
- for i := len(path) - 1; i >= 0 && !isSeparator(path[i]); i-- {
+ for i := len(path) - 1; i >= 0 && !os.IsPathSeparator(path[i]); i-- {
if path[i] == '.' {
return path[i:]
}
@@ -178,6 +179,14 @@ func Ext(path string) string {
// links.
// If path is relative it will be evaluated relative to the current directory.
func EvalSymlinks(path string) (string, os.Error) {
+ if runtime.GOOS == "windows" {
+ // Symlinks are not supported under windows.
+ _, err := os.Lstat(path)
+ if err != nil {
+ return "", err
+ }
+ return Clean(path), nil
+ }
const maxIter = 255
originalPath := path
// consume path by taking each frontmost path element,
@@ -225,7 +234,7 @@ func EvalSymlinks(path string) (string, os.Error) {
if IsAbs(dest) {
b.Reset()
}
- path = dest + SeparatorString + path
+ path = dest + string(Separator) + path
}
return Clean(b.String()), nil
}
@@ -236,7 +245,7 @@ func EvalSymlinks(path string) (string, os.Error) {
// path name for a given file is not guaranteed to be unique.
func Abs(path string) (string, os.Error) {
if IsAbs(path) {
- return path, nil
+ return Clean(path), nil
}
wd, err := os.Getwd()
if err != nil {
@@ -330,12 +339,12 @@ func Base(path string) string {
return "."
}
// Strip trailing slashes.
- for len(path) > 0 && isSeparator(path[len(path)-1]) {
+ for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
path = path[0 : len(path)-1]
}
// Find the last element
i := len(path) - 1
- for i >= 0 && !isSeparator(path[i]) {
+ for i >= 0 && !os.IsPathSeparator(path[i]) {
i--
}
if i >= 0 {
@@ -343,7 +352,7 @@ func Base(path string) string {
}
// If empty now, it had only slashes.
if path == "" {
- return SeparatorString
+ return string(Separator)
}
return path
}
diff --git a/libgo/go/path/filepath/path_plan9.go b/libgo/go/path/filepath/path_plan9.go
index e40008364cf..17b873f1a9b 100644
--- a/libgo/go/path/filepath/path_plan9.go
+++ b/libgo/go/path/filepath/path_plan9.go
@@ -6,23 +6,18 @@ package filepath
import "strings"
-const (
- Separator = '/' // OS-specific path separator
- ListSeparator = 0 // OS-specific path list separator
-)
-
-// isSeparator returns true if c is a directory separator character.
-func isSeparator(c uint8) bool {
- return Separator == c
-}
-
// IsAbs returns true if the path is absolute.
func IsAbs(path string) bool {
return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
}
-// volumeName returns the leading volume name on Windows.
+// VolumeName returns the leading volume name on Windows.
// It returns "" elsewhere
-func volumeName(path string) string {
+func VolumeName(path string) string {
return ""
}
+
+// HasPrefix tests whether the path p begins with prefix.
+func HasPrefix(p, prefix string) bool {
+ return strings.HasPrefix(p, prefix)
+}
diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go
index 37078f63af9..e944bf4edb0 100644
--- a/libgo/go/path/filepath/path_test.go
+++ b/libgo/go/path/filepath/path_test.go
@@ -66,9 +66,27 @@ var cleantests = []PathTest{
{"abc/../../././../def", "../../def"},
}
+var wincleantests = []PathTest{
+ {`c:`, `c:.`},
+ {`c:\`, `c:\`},
+ {`c:\abc`, `c:\abc`},
+ {`c:abc\..\..\.\.\..\def`, `c:..\..\def`},
+ {`c:\abc\def\..\..`, `c:\`},
+ {`c:..\abc`, `c:..\abc`},
+ {`\`, `\`},
+ {`/`, `\`},
+}
+
func TestClean(t *testing.T) {
- for _, test := range cleantests {
- if s := filepath.ToSlash(filepath.Clean(test.path)); s != test.result {
+ tests := cleantests
+ if runtime.GOOS == "windows" {
+ for i, _ := range tests {
+ tests[i].result = filepath.FromSlash(tests[i].result)
+ }
+ tests = append(tests, wincleantests...)
+ }
+ for _, test := range tests {
+ if s := filepath.Clean(test.path); s != test.result {
t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
}
}
@@ -292,10 +310,6 @@ func (v *TestVisitor) VisitFile(path string, f *os.FileInfo) {
}
func TestWalk(t *testing.T) {
- // TODO(brainman): enable test once Windows version is implemented.
- if runtime.GOOS == "windows" {
- return
- }
makeTree(t)
// 1) ignore error handling, expect none
@@ -314,7 +328,10 @@ func TestWalk(t *testing.T) {
}
checkMarks(t)
- if os.Getuid() > 0 {
+ // Test permission errors. Only possible if we're not root
+ // and only on some file systems (AFS, FAT). To avoid errors during
+ // all.bash on those file systems, skip during gotest -short.
+ if os.Getuid() > 0 && !testing.Short() {
// introduce 2 errors: chmod top-level directories to 0
os.Chmod(filepath.Join(tree.name, tree.entries[1].name), 0)
os.Chmod(filepath.Join(tree.name, tree.entries[3].name), 0)
@@ -399,16 +416,30 @@ var winisabstests = []IsAbsTest{
{`C:\`, true},
{`c\`, false},
{`c::`, false},
- {`/`, true},
- {`\`, true},
- {`\Windows`, true},
+ {`c:`, false},
+ {`/`, false},
+ {`\`, false},
+ {`\Windows`, false},
+ {`c:a\b`, false},
}
func TestIsAbs(t *testing.T) {
+ var tests []IsAbsTest
if runtime.GOOS == "windows" {
- isabstests = append(isabstests, winisabstests...)
+ tests = append(tests, winisabstests...)
+ // All non-windows tests should fail, because they have no volume letter.
+ for _, test := range isabstests {
+ tests = append(tests, IsAbsTest{test.path, false})
+ }
+ // All non-windows test should work as intended if prefixed with volume letter.
+ for _, test := range isabstests {
+ tests = append(tests, IsAbsTest{"c:" + test.path, test.isAbs})
+ }
+ } else {
+ tests = isabstests
}
- for _, test := range isabstests {
+
+ for _, test := range tests {
if r := filepath.IsAbs(test.path); r != test.isAbs {
t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
}
@@ -439,31 +470,48 @@ var EvalSymlinksTests = []EvalSymlinksTest{
{"test/link2/link3/test", "test"},
}
-func TestEvalSymlinks(t *testing.T) {
- // Symlinks are not supported under windows.
- if runtime.GOOS == "windows" {
- return
+var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
+ {`c:\`, `c:\`},
+}
+
+func testEvalSymlinks(t *testing.T, tests []EvalSymlinksTest) {
+ for _, d := range tests {
+ if p, err := filepath.EvalSymlinks(d.path); err != nil {
+ t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
+ } else if filepath.Clean(p) != filepath.Clean(d.dest) {
+ t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
+ }
}
+}
+
+func TestEvalSymlinks(t *testing.T) {
defer os.RemoveAll("test")
for _, d := range EvalSymlinksTestDirs {
var err os.Error
if d.dest == "" {
err = os.Mkdir(d.path, 0755)
} else {
- err = os.Symlink(d.dest, d.path)
+ if runtime.GOOS != "windows" {
+ err = os.Symlink(d.dest, d.path)
+ }
}
if err != nil {
t.Fatal(err)
}
}
- // relative
- for _, d := range EvalSymlinksTests {
- if p, err := filepath.EvalSymlinks(d.path); err != nil {
- t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
- } else if p != d.dest {
- t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
+ var tests []EvalSymlinksTest
+ if runtime.GOOS == "windows" {
+ for _, d := range EvalSymlinksTests {
+ if d.path == d.dest {
+ // will test only real files and directories
+ tests = append(tests, d)
+ }
}
+ } else {
+ tests = EvalSymlinksTests
}
+ // relative
+ testEvalSymlinks(t, tests)
// absolute
/* These tests do not work in the gccgo test environment.
goroot, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
@@ -471,17 +519,16 @@ func TestEvalSymlinks(t *testing.T) {
t.Fatalf("EvalSymlinks(%q) error: %v", os.Getenv("GOROOT"), err)
}
testroot := filepath.Join(goroot, "src", "pkg", "path", "filepath")
- for _, d := range EvalSymlinksTests {
- a := EvalSymlinksTest{
- filepath.Join(testroot, d.path),
- filepath.Join(testroot, d.dest),
- }
- if p, err := filepath.EvalSymlinks(a.path); err != nil {
- t.Errorf("EvalSymlinks(%q) error: %v", a.path, err)
- } else if p != a.dest {
- t.Errorf("EvalSymlinks(%q)=%q, want %q", a.path, p, a.dest)
+ for i, d := range tests {
+ tests[i].path = filepath.Join(testroot, d.path)
+ tests[i].dest = filepath.Join(testroot, d.dest)
+ }
+ if runtime.GOOS == "windows" {
+ for _, d := range EvalSymlinksAbsWindowsTests {
+ tests = append(tests, d)
}
}
+ testEvalSymlinks(t, tests)
*/
}
@@ -496,6 +543,7 @@ var abstests = []string{
// Already absolute
"$GOROOT/src/Make.pkg",
+ "$GOROOT/src/../src/Make.pkg",
}
func TestAbs(t *testing.T) {
@@ -524,6 +572,9 @@ func TestAbs(t *testing.T) {
if !filepath.IsAbs(abspath) {
t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
}
+ if filepath.IsAbs(path) && abspath != filepath.Clean(path) {
+ t.Errorf("Abs(%q)=%q, isn't clean", path, abspath)
+ }
}
}
diff --git a/libgo/go/path/filepath/path_unix.go b/libgo/go/path/filepath/path_unix.go
index f8ac248fbb9..b2a4151c1a8 100644
--- a/libgo/go/path/filepath/path_unix.go
+++ b/libgo/go/path/filepath/path_unix.go
@@ -6,23 +6,18 @@ package filepath
import "strings"
-const (
- Separator = '/' // OS-specific path separator
- ListSeparator = ':' // OS-specific path list separator
-)
-
-// isSeparator returns true if c is a directory separator character.
-func isSeparator(c uint8) bool {
- return Separator == c
-}
-
// IsAbs returns true if the path is absolute.
func IsAbs(path string) bool {
return strings.HasPrefix(path, "/")
}
-// volumeName returns the leading volume name on Windows.
+// VolumeName returns the leading volume name on Windows.
// It returns "" elsewhere.
-func volumeName(path string) string {
+func VolumeName(path string) string {
return ""
}
+
+// HasPrefix tests whether the path p begins with prefix.
+func HasPrefix(p, prefix string) bool {
+ return strings.HasPrefix(p, prefix)
+}
diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go
index dbd1c1e401d..2535697fd9e 100644
--- a/libgo/go/path/filepath/path_windows.go
+++ b/libgo/go/path/filepath/path_windows.go
@@ -4,34 +4,43 @@
package filepath
-const (
- Separator = '\\' // OS-specific path separator
- ListSeparator = ':' // OS-specific path list separator
-)
-
-// isSeparator returns true if c is a directory separator character.
-func isSeparator(c uint8) bool {
- // NOTE: Windows accept / as path separator.
- return c == '\\' || c == '/'
-}
+import "strings"
// IsAbs returns true if the path is absolute.
-func IsAbs(path string) bool {
- return path != "" && (volumeName(path) != "" || isSeparator(path[0]))
+func IsAbs(path string) (b bool) {
+ v := VolumeName(path)
+ if v == "" {
+ return false
+ }
+ path = path[len(v):]
+ if path == "" {
+ return false
+ }
+ return path[0] == '/' || path[0] == '\\'
}
-// volumeName return leading volume name.
-// If given "C:\foo\bar", return "C:" on windows.
-func volumeName(path string) string {
- if path == "" {
+// VolumeName returns leading volume name.
+// Given "C:\foo\bar" it returns "C:" under windows.
+// On other platforms it returns "".
+func VolumeName(path string) (v string) {
+ if len(path) < 2 {
return ""
}
// with drive letter
c := path[0]
- if len(path) > 2 && path[1] == ':' && isSeparator(path[2]) &&
+ if path[1] == ':' &&
('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
'A' <= c && c <= 'Z') {
- return path[0:2]
+ return path[:2]
}
return ""
}
+
+// HasPrefix tests whether the path p begins with prefix.
+// It ignores case while comparing.
+func HasPrefix(p, prefix string) bool {
+ if strings.HasPrefix(p, prefix) {
+ return true
+ }
+ return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix))
+}
diff --git a/libgo/go/rand/rand_test.go b/libgo/go/rand/rand_test.go
index 2476ebaf61d..3ebc1141d1a 100644
--- a/libgo/go/rand/rand_test.go
+++ b/libgo/go/rand/rand_test.go
@@ -45,12 +45,12 @@ func (this *statsResults) checkSimilarDistribution(expected *statsResults) os.Er
if !nearEqual(this.mean, expected.mean, expected.closeEnough, expected.maxError) {
s := fmt.Sprintf("mean %v != %v (allowed error %v, %v)", this.mean, expected.mean, expected.closeEnough, expected.maxError)
fmt.Println(s)
- return os.ErrorString(s)
+ return os.NewError(s)
}
if !nearEqual(this.stddev, expected.stddev, 0, expected.maxError) {
s := fmt.Sprintf("stddev %v != %v (allowed error %v, %v)", this.stddev, expected.stddev, expected.closeEnough, expected.maxError)
fmt.Println(s)
- return os.ErrorString(s)
+ return os.NewError(s)
}
return nil
}
@@ -197,7 +197,7 @@ func initNorm() (testKn []uint32, testWn, testFn []float32) {
const m1 = 1 << 31
var (
dn float64 = rn
- tn = dn
+ tn = dn
vn float64 = 9.91256303526217e-3
)
@@ -226,7 +226,7 @@ func initExp() (testKe []uint32, testWe, testFe []float32) {
const m2 = 1 << 32
var (
de float64 = re
- te = de
+ te = de
ve float64 = 3.9496598225815571993e-3
)
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 145fd520f5d..b8c609ab87e 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -127,17 +127,17 @@ var typeTests = []pair{
},
{struct {
x struct {
- a int8 "hi there"
+ a int8 `reflect:"hi there"`
}
}{},
- `struct { a int8 "hi there" }`,
+ `struct { a int8 "reflect:\"hi there\"" }`,
},
{struct {
x struct {
- a int8 "hi \x00there\t\n\"\\"
+ a int8 `reflect:"hi \x00there\t\n\"\\"`
}
}{},
- `struct { a int8 "hi \x00there\t\n\"\\" }`,
+ `struct { a int8 "reflect:\"hi \\x00there\\t\\n\\\"\\\\\"" }`,
},
{struct {
x struct {
@@ -380,7 +380,6 @@ func TestMapSetNil(t *testing.T) {
}
}
-
func TestAll(t *testing.T) {
testType(t, 1, TypeOf((int8)(0)), "int8")
testType(t, 2, TypeOf((*int8)(nil)).Elem(), "int8")
@@ -423,7 +422,7 @@ func TestAll(t *testing.T) {
// make sure tag strings are not part of element type
typ = TypeOf(struct {
- d []uint32 "TAG"
+ d []uint32 `reflect:"TAG"`
}{}).Field(0).Type
testType(t, 14, typ, "[]uint32")
}
@@ -744,7 +743,6 @@ func TestDeepEqualUnexportedMap(t *testing.T) {
}
}
-
func check2ndField(x interface{}, offs uintptr, t *testing.T) {
s := ValueOf(x)
f := s.Type().Field(1)
@@ -1050,6 +1048,12 @@ type Point struct {
x, y int
}
+// This will be index 0.
+func (p Point) AnotherMethod(scale int) int {
+ return -1
+}
+
+// This will be index 1.
func (p Point) Dist(scale int) int {
// println("Point.Dist", p.x, p.y, scale)
return p.x*p.x*scale + p.y*p.y*scale
@@ -1058,26 +1062,52 @@ func (p Point) Dist(scale int) int {
func TestMethod(t *testing.T) {
// Non-curried method of type.
p := Point{3, 4}
- i := TypeOf(p).Method(0).Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
+ i := TypeOf(p).Method(1).Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Type Method returned %d; want 250", i)
}
- i = TypeOf(&p).Method(0).Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
+ m, ok := TypeOf(p).MethodByName("Dist")
+ if !ok {
+ t.Fatalf("method by name failed")
+ }
+ m.Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Type MethodByName returned %d; want 250", i)
+ }
+
+ i = TypeOf(&p).Method(1).Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Pointer Type Method returned %d; want 250", i)
}
+ m, ok = TypeOf(&p).MethodByName("Dist")
+ if !ok {
+ t.Fatalf("ptr method by name failed")
+ }
+ i = m.Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Pointer Type MethodByName returned %d; want 250", i)
+ }
+
// Curried method of value.
- i = ValueOf(p).Method(0).Call([]Value{ValueOf(10)})[0].Int()
+ i = ValueOf(p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Value Method returned %d; want 250", i)
}
+ i = ValueOf(p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Value MethodByName returned %d; want 250", i)
+ }
// Curried method of pointer.
- i = ValueOf(&p).Method(0).Call([]Value{ValueOf(10)})[0].Int()
+ i = ValueOf(&p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
- t.Errorf("Value Method returned %d; want 250", i)
+ t.Errorf("Pointer Value Method returned %d; want 250", i)
+ }
+ i = ValueOf(&p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Pointer Value MethodByName returned %d; want 250", i)
}
// Curried method of interface value.
@@ -1094,6 +1124,10 @@ func TestMethod(t *testing.T) {
if i != 250 {
t.Errorf("Interface Method returned %d; want 250", i)
}
+ i = pv.MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ if i != 250 {
+ t.Errorf("Interface MethodByName returned %d; want 250", i)
+ }
}
func TestInterfaceSet(t *testing.T) {
@@ -1293,8 +1327,8 @@ func TestImportPath(t *testing.T) {
}
}
-func TestDotDotDot(t *testing.T) {
- // Test example from FuncType.DotDotDot documentation.
+func TestVariadicType(t *testing.T) {
+ // Test example from Type documentation.
var f func(x int, y ...float64)
typ := TypeOf(f)
if typ.NumIn() == 2 && typ.In(0) == TypeOf(int(0)) {
@@ -1453,7 +1487,9 @@ func noAlloc(t *testing.T, n int, f func(int)) {
for j := 0; j < n; j++ {
f(j)
}
- if runtime.MemStats.Mallocs != 0 {
+ // A few allocs may happen in the testing package when GOMAXPROCS > 1, so don't
+ // require zero mallocs.
+ if runtime.MemStats.Mallocs > 5 {
t.Fatalf("%d mallocs after %d iterations", runtime.MemStats.Mallocs, n)
}
}
@@ -1510,3 +1546,23 @@ func TestVariadic(t *testing.T) {
t.Errorf("after Fprintf CallSlice: %q != %q", b.String(), "hello 42 world")
}
}
+
+var tagGetTests = []struct {
+ Tag StructTag
+ Key string
+ Value string
+}{
+ {`protobuf:"PB(1,2)"`, `protobuf`, `PB(1,2)`},
+ {`protobuf:"PB(1,2)"`, `foo`, ``},
+ {`protobuf:"PB(1,2)"`, `rotobuf`, ``},
+ {`protobuf:"PB(1,2)" json:"name"`, `json`, `name`},
+ {`protobuf:"PB(1,2)" json:"name"`, `protobuf`, `PB(1,2)`},
+}
+
+func TestTagGet(t *testing.T) {
+ for _, tt := range tagGetTests {
+ if v := tt.Tag.Get(tt.Key); v != tt.Value {
+ t.Errorf("StructTag(%#q).Get(%#q) = %#q, want %#q", tt.Tag, tt.Key, v, tt.Value)
+ }
+ }
+}
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 30bf54a1f18..b825768568f 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -47,6 +47,16 @@ type Type interface {
// method signature, without a receiver, and the Func field is nil.
Method(int) Method
+ // MethodByName returns the method with that name in the type's
+ // method set and a boolean indicating if the method was found.
+ //
+ // For a non-interface type T or *T, the returned Method's Type and Func
+ // fields describe a function whose first argument is the receiver.
+ //
+ // For an interface type, the returned Method's Type field gives the
+ // method signature, without a receiver, and the Func field is nil.
+ MethodByName(string) (Method, bool)
+
// NumMethod returns the number of methods in the type's method set.
NumMethod() int
@@ -104,11 +114,11 @@ type Type interface {
// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
// implicit actual type []T.
//
- // For concreteness, if t represents func(x int, y ... float), then
+ // For concreteness, if t represents func(x int, y ... float64), then
//
// t.NumIn() == 2
// t.In(0) is the reflect.Type for "int"
- // t.In(1) is the reflect.Type for "[]float"
+ // t.In(1) is the reflect.Type for "[]float64"
// t.IsVariadic() == true
//
// IsVariadic panics if the type's Kind is not Func.
@@ -222,8 +232,8 @@ const (
// 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.
+// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
+// so that code cannot convert from, say, *arrayType to *ptrType.
type commonType struct {
kind uint8
@@ -261,10 +271,9 @@ const (
BothDir = RecvDir | SendDir
)
-
// arrayType represents a fixed array type.
type arrayType struct {
- commonType "array"
+ commonType `reflect:"array"`
elem *runtime.Type
slice *runtime.Type
len uintptr
@@ -272,14 +281,14 @@ type arrayType struct {
// chanType represents a channel type.
type chanType struct {
- commonType "chan"
+ commonType `reflect:"chan"`
elem *runtime.Type
dir uintptr
}
// funcType represents a function type.
type funcType struct {
- commonType "func"
+ commonType `reflect:"func"`
dotdotdot bool
in []*runtime.Type
out []*runtime.Type
@@ -294,26 +303,26 @@ type imethod struct {
// interfaceType represents an interface type.
type interfaceType struct {
- commonType "interface"
+ commonType `reflect:"interface"`
methods []imethod
}
// mapType represents a map type.
type mapType struct {
- commonType "map"
+ commonType `reflect:"map"`
key *runtime.Type
elem *runtime.Type
}
// ptrType represents a pointer type.
type ptrType struct {
- commonType "ptr"
+ commonType `reflect:"ptr"`
elem *runtime.Type
}
// sliceType represents a slice type.
type sliceType struct {
- commonType "slice"
+ commonType `reflect:"slice"`
elem *runtime.Type
}
@@ -328,11 +337,10 @@ type structField struct {
// structType represents a struct type.
type structType struct {
- commonType "struct"
+ commonType `reflect:"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.
@@ -344,6 +352,7 @@ type Method struct {
Name string
Type Type
Func Value
+ Index int
}
// High bit says whether type has
@@ -437,7 +446,7 @@ func (t *commonType) common() *commonType { return t }
func (t *uncommonType) Method(i int) (m Method) {
if t == nil || i < 0 || i >= len(t.methods) {
- return
+ panic("reflect: Method index out of range")
}
p := &t.methods[i]
if p.name != nil {
@@ -452,6 +461,7 @@ func (t *uncommonType) Method(i int) (m Method) {
x := new(unsafe.Pointer)
*x = p.tfn
m.Func = valueFromIword(flag, m.Type, iword(uintptr(unsafe.Pointer(x))))
+ m.Index = i
return
}
@@ -462,6 +472,20 @@ func (t *uncommonType) NumMethod() int {
return len(t.methods)
}
+func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
+ if t == nil {
+ return
+ }
+ var p *method
+ for i := range t.methods {
+ p = &t.methods[i]
+ if p.name != nil && *p.name == name {
+ return t.Method(i), true
+ }
+ }
+ return
+}
+
// TODO(rsc): 6g supplies these, but they are not
// as efficient as they could be: they have commonType
// as the receiver instead of *commonType.
@@ -481,6 +505,14 @@ func (t *commonType) Method(i int) (m Method) {
return t.uncommonType.Method(i)
}
+func (t *commonType) MethodByName(name string) (m Method, ok bool) {
+ if t.Kind() == Interface {
+ tt := (*interfaceType)(unsafe.Pointer(t))
+ return tt.MethodByName(name)
+ }
+ return t.uncommonType.MethodByName(name)
+}
+
func (t *commonType) PkgPath() string {
return t.uncommonType.PkgPath()
}
@@ -637,22 +669,98 @@ func (t *interfaceType) Method(i int) (m Method) {
m.PkgPath = *p.pkgPath
}
m.Type = toType(p.typ)
+ m.Index = i
return
}
// NumMethod returns the number of interface methods in the type's method set.
func (t *interfaceType) NumMethod() int { return len(t.methods) }
+// MethodByName method with the given name in the type's method set.
+func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
+ if t == nil {
+ return
+ }
+ var p *imethod
+ for i := range t.methods {
+ p = &t.methods[i]
+ if *p.name == name {
+ return t.Method(i), true
+ }
+ }
+ return
+}
+
type StructField struct {
PkgPath string // empty for uppercase Name
Name string
Type Type
- Tag string
+ Tag StructTag
Offset uintptr
Index []int
Anonymous bool
}
+// A StructTag is the tag string in a struct field.
+//
+// By convention, tag strings are a concatenation of
+// optionally space-separated key:"value" pairs.
+// Each key is a non-empty string consisting of non-control
+// characters other than space (U+0020 ' '), quote (U+0022 '"'),
+// and colon (U+003A ':'). Each value is quoted using U+0022 '"'
+// characters and Go string literal syntax.
+type StructTag string
+
+// Get returns the value associated with key in the tag string.
+// If there is no such key in the tag, Get returns the empty string.
+// If the tag does not have the conventional format, the value
+// returned by Get is unspecified,
+func (tag StructTag) Get(key string) string {
+ for tag != "" {
+ // skip leading space
+ i := 0
+ for i < len(tag) && tag[i] == ' ' {
+ i++
+ }
+ tag = tag[i:]
+ if tag == "" {
+ break
+ }
+
+ // scan to colon.
+ // a space or a quote is a syntax error
+ i = 0
+ for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
+ i++
+ }
+ if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
+ break
+ }
+ name := string(tag[:i])
+ tag = tag[i+1:]
+
+ // scan quoted string to find value
+ i = 1
+ for i < len(tag) && tag[i] != '"' {
+ if tag[i] == '\\' {
+ i++
+ }
+ i++
+ }
+ if i >= len(tag) {
+ break
+ }
+ qvalue := string(tag[:i+1])
+ tag = tag[i+1:]
+
+ if key == name {
+ value, _ := strconv.Unquote(qvalue)
+ return value
+ }
+ }
+ return ""
+}
+
// Field returns the i'th struct field.
func (t *structType) Field(i int) (f StructField) {
if i < 0 || i >= len(t.fields) {
@@ -674,7 +782,7 @@ func (t *structType) Field(i int) (f StructField) {
f.PkgPath = *p.pkgPath
}
if p.tag != nil {
- f.Tag = *p.tag
+ f.Tag = StructTag(*p.tag)
}
f.Offset = p.offset
f.Index = []int{i}
@@ -793,7 +901,7 @@ func toCommonType(p *runtime.Type) *commonType {
}
x := unsafe.Pointer(p)
if uintptr(x)&reflectFlags != 0 {
- panic("invalid interface value")
+ panic("reflect: invalid interface value")
}
return (*commonType)(x)
}
@@ -890,8 +998,8 @@ func PtrTo(t Type) Type {
rp := new(runtime.PtrType)
- // initialize p using *byte's PtrType as a prototype.
- // have to do assignment as PtrType, not runtime.PtrType,
+ // initialize p using *byte's ptrType as a prototype.
+ // have to do assignment as ptrType, not runtime.PtrType,
// in order to write to unexported fields.
p = (*ptrType)(unsafe.Pointer(rp))
bp := (*ptrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index ea48b02f14b..6675a9a08d5 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -11,7 +11,7 @@ import (
"unsafe"
)
-const ptrSize = uintptr(unsafe.Sizeof((*byte)(nil)))
+const ptrSize = unsafe.Sizeof((*byte)(nil))
const cannotSet = "cannot set value obtained from unexported struct field"
// TODO: This will have to go away when
@@ -169,7 +169,7 @@ type nonEmptyInterface struct {
// Regarding the implementation of Value:
//
// The Internal interface is a true interface value in the Go sense,
-// but it also serves as a (type, address) pair in whcih one cannot
+// but it also serves as a (type, address) pair in which one cannot
// be changed separately from the other. That is, it serves as a way
// to prevent unsafe mutations of the Internal state even though
// we cannot (yet?) hide the field while preserving the ability for
@@ -558,7 +558,16 @@ func (iv internalValue) call(method string, in []Value) []Value {
ret[i] = Indirect(v)
}
- call(t, *(*unsafe.Pointer)(iv.addr), iv.method, first_pointer, &params[0], &results[0])
+ var pp *unsafe.Pointer
+ if len(params) > 0 {
+ pp = &params[0]
+ }
+ var pr *unsafe.Pointer
+ if len(results) > 0 {
+ pr = &results[0]
+ }
+
+ call(t, *(*unsafe.Pointer)(iv.addr), iv.method, first_pointer, pp, pr)
return ret
}
@@ -839,6 +848,9 @@ func (v Value) Interface() interface{} {
}
func (iv internalValue) Interface() interface{} {
+ if iv.kind == 0 {
+ panic(&ValueError{"reflect.Value.Interface", iv.kind})
+ }
if iv.method {
panic("reflect.Value.Interface: cannot create interface value for method with bound receiver")
}
@@ -917,7 +929,7 @@ func (v Value) Kind() Kind {
}
// Len returns v's length.
-// It panics if v's Kind is not Array, Chan, Map, or Slice.
+// It panics if v's Kind is not Array, Chan, Map, Slice, or String.
func (v Value) Len() int {
iv := v.internal()
switch iv.kind {
@@ -929,6 +941,8 @@ func (v Value) Len() int {
return int(maplen(*(*iword)(iv.addr)))
case Slice:
return (*SliceHeader)(iv.addr).Len
+ case String:
+ return (*StringHeader)(iv.addr).Len
}
panic(&ValueError{"reflect.Value.Len", iv.kind})
}
@@ -956,7 +970,7 @@ func (v Value) MapIndex(key Value) Value {
flag := (iv.flag | ikey.flag) & flagRO
elemType := typ.Elem()
- elemWord, ok := mapaccess(*(*iword)(iv.addr), ikey.word)
+ elemWord, ok := mapaccess(typ.runtimeType(), *(*iword)(iv.addr), ikey.word)
if !ok {
return Value{}
}
@@ -978,7 +992,7 @@ func (v Value) MapKeys() []Value {
if m != 0 {
mlen = maplen(m)
}
- it := mapiterinit(m)
+ it := mapiterinit(iv.typ.runtimeType(), m)
a := make([]Value, mlen)
var i int
for i = 0; i < len(a); i++ {
@@ -1007,6 +1021,32 @@ func (v Value) Method(i int) Value {
return Value{v.Internal, i + 1}
}
+// NumMethod returns the number of methods in the value's method set.
+func (v Value) NumMethod() int {
+ iv := v.internal()
+ if iv.kind == Invalid {
+ panic(&ValueError{"reflect.Value.NumMethod", Invalid})
+ }
+ return iv.typ.NumMethod()
+}
+
+// MethodByName returns a function value corresponding to the method
+// of v with the given name.
+// The arguments to a Call on the returned function should not include
+// a receiver; the returned function will always use v as the receiver.
+// It returns the zero Value if no method was found.
+func (v Value) MethodByName(name string) Value {
+ iv := v.internal()
+ if iv.kind == Invalid {
+ panic(&ValueError{"reflect.Value.MethodByName", Invalid})
+ }
+ m, ok := iv.typ.MethodByName(name)
+ if ok {
+ return Value{v.Internal, m.Index + 1}
+ }
+ return Value{}
+}
+
// NumField returns the number of fields in the struct v.
// It panics if v's Kind is not Struct.
func (v Value) NumField() int {
@@ -1120,7 +1160,7 @@ func (iv internalValue) recv(nb bool) (val Value, ok bool) {
if ch == 0 {
panic("recv on nil channel")
}
- valWord, selected, ok := chanrecv(ch, nb)
+ valWord, selected, ok := chanrecv(iv.typ.runtimeType(), ch, nb)
if selected {
val = valueFromIword(0, t.Elem(), valWord)
}
@@ -1150,7 +1190,7 @@ func (iv internalValue) send(x Value, nb bool) (selected bool) {
if ch == 0 {
panic("send on nil channel")
}
- return chansend(ch, ix.word, nb)
+ return chansend(iv.typ.runtimeType(), ch, ix.word, nb)
}
// Set assigns x to the value v.
@@ -1267,7 +1307,7 @@ func (v Value) SetMapIndex(key, val Value) {
ival = convertForAssignment("reflect.Value.SetMapIndex", nil, iv.typ.Elem(), ival)
}
- mapassign(*(*iword)(iv.addr), ikey.word, ival.word, ival.kind != Invalid)
+ mapassign(iv.typ.runtimeType(), *(*iword)(iv.addr), ikey.word, ival.word, ival.kind != Invalid)
}
// SetUint sets v's underlying value to x.
@@ -1675,14 +1715,14 @@ func convertForAssignment(what string, addr unsafe.Pointer, dst Type, iv interna
func chancap(ch iword) int32
func chanclose(ch iword)
func chanlen(ch iword) int32
-func chanrecv(ch iword, nb bool) (val iword, selected, received bool)
-func chansend(ch iword, val iword, nb bool) bool
+func chanrecv(t *runtime.Type, ch iword, nb bool) (val iword, selected, received bool)
+func chansend(t *runtime.Type, ch iword, val iword, nb bool) bool
func makechan(typ *runtime.Type, size uint32) (ch iword)
func makemap(t *runtime.Type) iword
-func mapaccess(m iword, key iword) (val iword, ok bool)
-func mapassign(m iword, key, val iword, ok bool)
-func mapiterinit(m iword) *byte
+func mapaccess(t *runtime.Type, m iword, key iword) (val iword, ok bool)
+func mapassign(t *runtime.Type, m iword, key, val iword, ok bool)
+func mapiterinit(t *runtime.Type, m iword) *byte
func mapiterkey(it *byte) (key iword, ok bool)
func mapiternext(it *byte)
func maplen(m iword) int32
diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go
index c7ee4c87970..71edc4d18d3 100644
--- a/libgo/go/regexp/all_test.go
+++ b/libgo/go/regexp/all_test.go
@@ -356,7 +356,7 @@ func BenchmarkMatchClass(b *testing.B) {
func BenchmarkMatchClass_InRange(b *testing.B) {
b.StopTimer()
- // 'b' is betwen 'a' and 'c', so the charclass
+ // 'b' is between 'a' and 'c', so the charclass
// range checking is no help here.
x := strings.Repeat("bbbb", 20) + "c"
re := MustCompile("[ac]")
diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go
index e3221ac9d68..e8d4c087cf8 100644
--- a/libgo/go/regexp/regexp.go
+++ b/libgo/go/regexp/regexp.go
@@ -87,16 +87,16 @@ func (e Error) String() string {
// Error codes returned by failures to parse an expression.
var (
- ErrInternal = Error("internal error")
- ErrUnmatchedLpar = Error("unmatched '('")
- ErrUnmatchedRpar = Error("unmatched ')'")
- ErrUnmatchedLbkt = Error("unmatched '['")
- ErrUnmatchedRbkt = Error("unmatched ']'")
- ErrBadRange = Error("bad range in character class")
- ErrExtraneousBackslash = Error("extraneous backslash")
- ErrBadClosure = Error("repeated closure (**, ++, etc.)")
- ErrBareClosure = Error("closure applies to nothing")
- ErrBadBackslash = Error("illegal backslash escape")
+ ErrInternal = Error("regexp: internal error")
+ ErrUnmatchedLpar = Error("regexp: unmatched '('")
+ ErrUnmatchedRpar = Error("regexp: unmatched ')'")
+ ErrUnmatchedLbkt = Error("regexp: unmatched '['")
+ ErrUnmatchedRbkt = Error("regexp: unmatched ']'")
+ ErrBadRange = Error("regexp: bad range in character class")
+ ErrExtraneousBackslash = Error("regexp: extraneous backslash")
+ ErrBadClosure = Error("regexp: repeated closure (**, ++, etc.)")
+ ErrBareClosure = Error("regexp: closure applies to nothing")
+ ErrBadBackslash = Error("regexp: illegal backslash escape")
)
const (
@@ -158,6 +158,7 @@ func (i *instr) print() {
// Regexp is the representation of a compiled regular expression.
// The public interface is entirely through methods.
+// A Regexp is safe for concurrent use by multiple goroutines.
type Regexp struct {
expr string // the original expression
prefix string // initial plain text string
diff --git a/libgo/go/rpc/client.go b/libgo/go/rpc/client.go
index 8af4afcf697..4acfdf6d962 100644
--- a/libgo/go/rpc/client.go
+++ b/libgo/go/rpc/client.go
@@ -23,7 +23,7 @@ func (e ServerError) String() string {
return string(e)
}
-const ErrShutdown = os.ErrorString("connection is shut down")
+var ErrShutdown = os.NewError("connection is shut down")
// Call represents an active RPC.
type Call struct {
@@ -110,7 +110,7 @@ func (client *Client) input() {
if response.Error == "" {
err = client.codec.ReadResponseBody(c.Reply)
if err != nil {
- c.Error = os.ErrorString("reading body " + err.String())
+ c.Error = os.NewError("reading body " + err.String())
}
} else {
// We've got an error response. Give this to the request;
@@ -119,7 +119,7 @@ func (client *Client) input() {
c.Error = ServerError(response.Error)
err = client.codec.ReadResponseBody(nil)
if err != nil {
- err = os.ErrorString("reading error body: " + err.String())
+ err = os.NewError("reading error body: " + err.String())
}
}
c.done()
@@ -197,7 +197,6 @@ 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) {
@@ -216,12 +215,12 @@ func DialHTTPPath(network, address, path string) (*Client, os.Error) {
// Require successful HTTP response
// before switching to RPC protocol.
- resp, err := http.ReadResponse(bufio.NewReader(conn), "CONNECT")
+ resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
if err == nil && resp.Status == connected {
return NewClient(conn), nil
}
if err == nil {
- err = os.ErrorString("unexpected HTTP response: " + resp.Status)
+ err = os.NewError("unexpected HTTP response: " + resp.Status)
}
conn.Close()
return nil, &net.OpError{"dial-http", network + " " + address, nil, err}
diff --git a/libgo/go/rpc/debug.go b/libgo/go/rpc/debug.go
index 32dc8a18ba2..7e3e6f6e5b7 100644
--- a/libgo/go/rpc/debug.go
+++ b/libgo/go/rpc/debug.go
@@ -19,24 +19,24 @@ import (
const debugText = `<html>
<body>
<title>Services</title>
- {.repeated section @}
+ {{range .}}
<hr>
- Service {Name}
+ Service {{.Name}}
<hr>
<table>
<th align=center>Method</th><th align=center>Calls</th>
- {.repeated section Method}
+ {{range .Method}}
<tr>
- <td align=left font=fixed>{Name}({Type.ArgType}, {Type.ReplyType}) os.Error</td>
- <td align=center>{Type.NumCalls}</td>
+ <td align=left font=fixed>{{.Name}}({{.Type.ArgType}}, {{.Type.ReplyType}}) os.Error</td>
+ <td align=center>{{.Type.NumCalls}}</td>
</tr>
- {.end}
+ {{end}}
</table>
- {.end}
+ {{end}}
</body>
</html>`
-var debug = template.MustParse(debugText, nil)
+var debug = template.Must(template.New("RPC debug").Parse(debugText))
type debugMethod struct {
Type *methodType
@@ -70,7 +70,7 @@ 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()
+ server.mu.Lock()
for sname, service := range server.serviceMap {
services[i] = debugService{service, sname, make(methodArray, len(service.method))}
j := 0
@@ -81,7 +81,7 @@ func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) {
sort.Sort(services[i].Method)
i++
}
- server.Unlock()
+ server.mu.Unlock()
sort.Sort(services)
err := debug.Execute(w, services)
if err != nil {
diff --git a/libgo/go/rpc/jsonrpc/all_test.go b/libgo/go/rpc/jsonrpc/all_test.go
index 764ee7ff361..c1a9e8ecbc5 100644
--- a/libgo/go/rpc/jsonrpc/all_test.go
+++ b/libgo/go/rpc/jsonrpc/all_test.go
@@ -35,7 +35,7 @@ func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
func (t *Arith) Div(args *Args, reply *Reply) os.Error {
if args.B == 0 {
- return os.ErrorString("divide by zero")
+ return os.NewError("divide by zero")
}
reply.C = args.A / args.B
return nil
@@ -51,9 +51,9 @@ func init() {
func TestServer(t *testing.T) {
type addResp struct {
- Id interface{} "id"
- Result Reply "result"
- Error interface{} "error"
+ Id interface{} `json:"id"`
+ Result Reply `json:"result"`
+ Error interface{} `json:"error"`
}
cli, srv := net.Pipe()
diff --git a/libgo/go/rpc/jsonrpc/client.go b/libgo/go/rpc/jsonrpc/client.go
index 57e977d3253..577d0ce4295 100644
--- a/libgo/go/rpc/jsonrpc/client.go
+++ b/libgo/go/rpc/jsonrpc/client.go
@@ -44,9 +44,9 @@ func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
}
type clientRequest struct {
- Method string "method"
- Params [1]interface{} "params"
- Id uint64 "id"
+ Method string `json:"method"`
+ Params [1]interface{} `json:"params"`
+ Id uint64 `json:"id"`
}
func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
@@ -60,9 +60,9 @@ func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
}
type clientResponse struct {
- Id uint64 "id"
- Result *json.RawMessage "result"
- Error interface{} "error"
+ Id uint64 `json:"id"`
+ Result *json.RawMessage `json:"result"`
+ Error interface{} `json:"error"`
}
func (r *clientResponse) reset() {
diff --git a/libgo/go/rpc/jsonrpc/server.go b/libgo/go/rpc/jsonrpc/server.go
index 9c6b8b40d68..9801fdf221e 100644
--- a/libgo/go/rpc/jsonrpc/server.go
+++ b/libgo/go/rpc/jsonrpc/server.go
@@ -43,9 +43,9 @@ func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec {
}
type serverRequest struct {
- Method string "method"
- Params *json.RawMessage "params"
- Id *json.RawMessage "id"
+ Method string `json:"method"`
+ Params *json.RawMessage `json:"params"`
+ Id *json.RawMessage `json:"id"`
}
func (r *serverRequest) reset() {
@@ -59,9 +59,9 @@ func (r *serverRequest) reset() {
}
type serverResponse struct {
- Id *json.RawMessage "id"
- Result interface{} "result"
- Error interface{} "error"
+ Id *json.RawMessage `json:"id"`
+ Result interface{} `json:"result"`
+ Error interface{} `json:"error"`
}
func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
diff --git a/libgo/go/rpc/server.go b/libgo/go/rpc/server.go
index acadeec37f0..74507442862 100644
--- a/libgo/go/rpc/server.go
+++ b/libgo/go/rpc/server.go
@@ -174,7 +174,7 @@ type Response struct {
// Server represents an RPC Server.
type Server struct {
- sync.Mutex // protects the serviceMap
+ mu sync.Mutex // protects the serviceMap
serviceMap map[string]*service
reqLock sync.Mutex // protects freeReq
freeReq *Request
@@ -196,12 +196,14 @@ func isExported(name string) bool {
return unicode.IsUpper(rune)
}
-// Is this type exported or local to this package?
-func isExportedOrLocalType(t reflect.Type) bool {
+// Is this type exported or a builtin?
+func isExportedOrBuiltinType(t reflect.Type) bool {
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
- return t.PkgPath() == "" || isExported(t.Name())
+ // PkgPath will be non-empty even for an exported type,
+ // so we need to check the type name as well.
+ return isExported(t.Name()) || t.PkgPath() == ""
}
// Register publishes in the server the set of methods of the
@@ -224,8 +226,8 @@ func (server *Server) RegisterName(name string, rcvr interface{}) os.Error {
}
func (server *Server) register(rcvr interface{}, name string, useName bool) os.Error {
- server.Lock()
- defer server.Unlock()
+ server.mu.Lock()
+ defer server.mu.Unlock()
if server.serviceMap == nil {
server.serviceMap = make(map[string]*service)
}
@@ -239,13 +241,13 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
if sname == "" {
log.Fatal("rpc: no service name for type", s.typ.String())
}
- if s.typ.PkgPath() != "" && !isExported(sname) && !useName {
+ if !isExported(sname) && !useName {
s := "rpc Register: type " + sname + " is not exported"
log.Print(s)
- return os.ErrorString(s)
+ return os.NewError(s)
}
if _, present := server.serviceMap[sname]; present {
- return os.ErrorString("rpc: service already defined: " + sname)
+ return os.NewError("rpc: service already defined: " + sname)
}
s.name = sname
s.method = make(map[string]*methodType)
@@ -255,7 +257,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
method := s.typ.Method(m)
mtype := method.Type
mname := method.Name
- if mtype.PkgPath() != "" || !isExported(mname) {
+ if method.PkgPath != "" {
continue
}
// Method needs three ins: receiver, *args, *reply.
@@ -265,7 +267,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
}
// First arg need not be a pointer.
argType := mtype.In(1)
- if !isExportedOrLocalType(argType) {
+ if !isExportedOrBuiltinType(argType) {
log.Println(mname, "argument type not exported or local:", argType)
continue
}
@@ -275,7 +277,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
log.Println("method", mname, "reply type not a pointer:", replyType)
continue
}
- if !isExportedOrLocalType(replyType) {
+ if !isExportedOrBuiltinType(replyType) {
log.Println("method", mname, "reply type not exported or local:", replyType)
continue
}
@@ -294,7 +296,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
if len(s.method) == 0 {
s := "rpc Register: type " + sname + " has no exported methods of suitable type"
log.Print(s)
- return os.ErrorString(s)
+ return os.NewError(s)
}
server.serviceMap[s.name] = s
return nil
@@ -376,7 +378,6 @@ 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.
@@ -393,7 +394,7 @@ func (server *Server) ServeConn(conn io.ReadWriteCloser) {
func (server *Server) ServeCodec(codec ServerCodec) {
sending := new(sync.Mutex)
for {
- req, service, mtype, err := server.readRequest(codec)
+ service, mtype, req, argv, replyv, err := server.readRequest(codec)
if err != nil {
if err != os.EOF {
log.Println("rpc:", err)
@@ -401,9 +402,6 @@ func (server *Server) ServeCodec(codec ServerCodec) {
if err == os.EOF || err == io.ErrUnexpectedEOF {
break
}
- // discard body
- codec.ReadRequestBody(nil)
-
// send a response if we actually managed to read a header.
if req != nil {
server.sendResponse(sending, req, invalidRequest, codec, err.String())
@@ -411,35 +409,29 @@ func (server *Server) ServeCodec(codec ServerCodec) {
}
continue
}
+ go service.call(server, sending, mtype, req, argv, replyv, codec)
+ }
+ codec.Close()
+}
- // Decode the argument value.
- var argv reflect.Value
- argIsValue := false // if true, need to indirect before calling.
- if mtype.ArgType.Kind() == reflect.Ptr {
- argv = reflect.New(mtype.ArgType.Elem())
- } else {
- argv = reflect.New(mtype.ArgType)
- argIsValue = true
- }
- // argv guaranteed to be a pointer now.
- replyv := reflect.New(mtype.ReplyType.Elem())
- err = codec.ReadRequestBody(argv.Interface())
- if err != nil {
- if err == os.EOF || err == io.ErrUnexpectedEOF {
- if err == io.ErrUnexpectedEOF {
- log.Println("rpc:", err)
- }
- break
- }
- server.sendResponse(sending, req, replyv.Interface(), codec, err.String())
- continue
+// ServeRequest is like ServeCodec but synchronously serves a single request.
+// It does not close the codec upon completion.
+func (server *Server) ServeRequest(codec ServerCodec) os.Error {
+ sending := new(sync.Mutex)
+ service, mtype, req, argv, replyv, err := server.readRequest(codec)
+ if err != nil {
+ if err == os.EOF || err == io.ErrUnexpectedEOF {
+ return err
}
- if argIsValue {
- argv = argv.Elem()
+ // send a response if we actually managed to read a header.
+ if req != nil {
+ server.sendResponse(sending, req, invalidRequest, codec, err.String())
+ server.freeRequest(req)
}
- go service.call(server, sending, mtype, req, argv, replyv, codec)
+ return err
}
- codec.Close()
+ service.call(server, sending, mtype, req, argv, replyv, codec)
+ return nil
}
func (server *Server) getRequest() *Request {
@@ -482,7 +474,38 @@ func (server *Server) freeResponse(resp *Response) {
server.respLock.Unlock()
}
-func (server *Server) readRequest(codec ServerCodec) (req *Request, service *service, mtype *methodType, err os.Error) {
+func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *methodType, req *Request, argv, replyv reflect.Value, err os.Error) {
+ service, mtype, req, err = server.readRequestHeader(codec)
+ if err != nil {
+ if err == os.EOF || err == io.ErrUnexpectedEOF {
+ return
+ }
+ // discard body
+ codec.ReadRequestBody(nil)
+ return
+ }
+
+ // Decode the argument value.
+ argIsValue := false // if true, need to indirect before calling.
+ if mtype.ArgType.Kind() == reflect.Ptr {
+ argv = reflect.New(mtype.ArgType.Elem())
+ } else {
+ argv = reflect.New(mtype.ArgType)
+ argIsValue = true
+ }
+ // argv guaranteed to be a pointer now.
+ if err = codec.ReadRequestBody(argv.Interface()); err != nil {
+ return
+ }
+ if argIsValue {
+ argv = argv.Elem()
+ }
+
+ replyv = reflect.New(mtype.ReplyType.Elem())
+ return
+}
+
+func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mtype *methodType, req *Request, err os.Error) {
// Grab the request header.
req = server.getRequest()
err = codec.ReadRequestHeader(req)
@@ -491,26 +514,26 @@ func (server *Server) readRequest(codec ServerCodec) (req *Request, service *ser
if err == os.EOF || err == io.ErrUnexpectedEOF {
return
}
- err = os.ErrorString("rpc: server cannot decode request: " + err.String())
+ err = os.NewError("rpc: server cannot decode request: " + err.String())
return
}
- serviceMethod := strings.Split(req.ServiceMethod, ".", -1)
+ serviceMethod := strings.Split(req.ServiceMethod, ".")
if len(serviceMethod) != 2 {
- err = os.ErrorString("rpc: service/method request ill-formed: " + req.ServiceMethod)
+ err = os.NewError("rpc: service/method request ill-formed: " + req.ServiceMethod)
return
}
// Look up the request.
- server.Lock()
+ server.mu.Lock()
service = server.serviceMap[serviceMethod[0]]
- server.Unlock()
+ server.mu.Unlock()
if service == nil {
- err = os.ErrorString("rpc: can't find service " + req.ServiceMethod)
+ err = os.NewError("rpc: can't find service " + req.ServiceMethod)
return
}
mtype = service.method[serviceMethod[1]]
if mtype == nil {
- err = os.ErrorString("rpc: can't find method " + req.ServiceMethod)
+ err = os.NewError("rpc: can't find method " + req.ServiceMethod)
}
return
}
@@ -567,6 +590,12 @@ func ServeCodec(codec ServerCodec) {
DefaultServer.ServeCodec(codec)
}
+// ServeRequest is like ServeCodec but synchronously serves a single request.
+// It does not close the codec upon completion.
+func ServeRequest(codec ServerCodec) os.Error {
+ return DefaultServer.ServeRequest(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.
diff --git a/libgo/go/rpc/server_test.go b/libgo/go/rpc/server_test.go
index cfff0c9ad50..e7bbfbe97d2 100644
--- a/libgo/go/rpc/server_test.go
+++ b/libgo/go/rpc/server_test.go
@@ -7,6 +7,7 @@ package rpc
import (
"fmt"
"http/httptest"
+ "io"
"log"
"net"
"os"
@@ -18,6 +19,7 @@ import (
)
var (
+ newServer *Server
serverAddr, newServerAddr string
httpServerAddr string
once, newOnce, httpOnce sync.Once
@@ -52,7 +54,7 @@ func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
func (t *Arith) Div(args Args, reply *Reply) os.Error {
if args.B == 0 {
- return os.ErrorString("divide by zero")
+ return os.NewError("divide by zero")
}
reply.C = args.A / args.B
return nil
@@ -93,15 +95,15 @@ func startServer() {
}
func startNewServer() {
- s := NewServer()
- s.Register(new(Arith))
+ newServer = NewServer()
+ newServer.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")
+ newServer.HandleHTTP(newHttpPath, "/bar")
httpOnce.Do(startHttpServer)
}
@@ -264,6 +266,85 @@ func testHTTPRPC(t *testing.T, path string) {
}
}
+// CodecEmulator provides a client-like api and a ServerCodec interface.
+// Can be used to test ServeRequest.
+type CodecEmulator struct {
+ server *Server
+ serviceMethod string
+ args *Args
+ reply *Reply
+ err os.Error
+}
+
+func (codec *CodecEmulator) Call(serviceMethod string, args *Args, reply *Reply) os.Error {
+ codec.serviceMethod = serviceMethod
+ codec.args = args
+ codec.reply = reply
+ codec.err = nil
+ var serverError os.Error
+ if codec.server == nil {
+ serverError = ServeRequest(codec)
+ } else {
+ serverError = codec.server.ServeRequest(codec)
+ }
+ if codec.err == nil && serverError != nil {
+ codec.err = serverError
+ }
+ return codec.err
+}
+
+func (codec *CodecEmulator) ReadRequestHeader(req *Request) os.Error {
+ req.ServiceMethod = codec.serviceMethod
+ req.Seq = 0
+ return nil
+}
+
+func (codec *CodecEmulator) ReadRequestBody(argv interface{}) os.Error {
+ if codec.args == nil {
+ return io.ErrUnexpectedEOF
+ }
+ *(argv.(*Args)) = *codec.args
+ return nil
+}
+
+func (codec *CodecEmulator) WriteResponse(resp *Response, reply interface{}) os.Error {
+ if resp.Error != "" {
+ codec.err = os.NewError(resp.Error)
+ }
+ *codec.reply = *(reply.(*Reply))
+ return nil
+}
+
+func (codec *CodecEmulator) Close() os.Error {
+ return nil
+}
+
+func TestServeRequest(t *testing.T) {
+ once.Do(startServer)
+ testServeRequest(t, nil)
+ newOnce.Do(startNewServer)
+ testServeRequest(t, newServer)
+}
+
+func testServeRequest(t *testing.T, server *Server) {
+ client := CodecEmulator{server: server}
+
+ 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)
+ }
+
+ err = client.Call("Arith.Add", nil, reply)
+ if err == nil {
+ t.Errorf("expected error calling Arith.Add with nil arg")
+ }
+}
+
type ReplyNotPointer int
type ArgNotPublic int
type ReplyNotPublic int
@@ -360,6 +441,7 @@ func countMallocs(dial func() (*Client, os.Error), t *testing.T) uint64 {
}
args := &Args{7, 8}
reply := new(Reply)
+ runtime.UpdateMemStats()
mallocs := 0 - runtime.MemStats.Mallocs
const count = 100
for i := 0; i < count; i++ {
@@ -371,6 +453,7 @@ func countMallocs(dial func() (*Client, os.Error), t *testing.T) uint64 {
t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
}
}
+ runtime.UpdateMemStats()
mallocs += runtime.MemStats.Mallocs
return mallocs / count
}
diff --git a/libgo/go/runtime/append_test.go b/libgo/go/runtime/append_test.go
new file mode 100644
index 00000000000..b8552224e5b
--- /dev/null
+++ b/libgo/go/runtime/append_test.go
@@ -0,0 +1,52 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package runtime_test
+
+import "testing"
+
+const N = 20
+
+func BenchmarkAppend(b *testing.B) {
+ b.StopTimer()
+ x := make([]int, 0, N)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ x = x[0:0]
+ for j := 0; j < N; j++ {
+ x = append(x, j)
+ }
+ }
+}
+
+func BenchmarkAppendSpecialCase(b *testing.B) {
+ b.StopTimer()
+ x := make([]int, 0, N)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ x = x[0:0]
+ for j := 0; j < N; j++ {
+ if len(x) < cap(x) {
+ x = x[:len(x)+1]
+ x[len(x)-1] = j
+ } else {
+ x = append(x, j)
+ }
+ }
+ }
+}
+
+var x []int
+
+func f() int {
+ x[:1][0] = 3
+ return 2
+}
+
+func TestSideEffectOrder(t *testing.T) {
+ x = make([]int, 0, 10)
+ x = append(x, 1, f())
+ if x[0] != 1 || x[1] != 2 {
+ t.Error("append failed: ", x[0], x[1])
+ }
+}
diff --git a/libgo/go/runtime/chan_test.go b/libgo/go/runtime/chan_test.go
new file mode 100644
index 00000000000..46ddfd7e88f
--- /dev/null
+++ b/libgo/go/runtime/chan_test.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 runtime_test
+
+import (
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "testing"
+)
+
+func TestChanSendInterface(t *testing.T) {
+ type mt struct{}
+ m := &mt{}
+ c := make(chan interface{}, 1)
+ c <- m
+ select {
+ case c <- m:
+ default:
+ }
+ select {
+ case c <- m:
+ case c <- &mt{}:
+ default:
+ }
+}
+
+func TestPseudoRandomSend(t *testing.T) {
+ n := 100
+ c := make(chan int)
+ l := make([]int, n)
+ var m sync.Mutex
+ m.Lock()
+ go func() {
+ for i := 0; i < n; i++ {
+ runtime.Gosched()
+ l[i] = <-c
+ }
+ m.Unlock()
+ }()
+ for i := 0; i < n; i++ {
+ select {
+ case c <- 0:
+ case c <- 1:
+ }
+ }
+ m.Lock() // wait
+ n0 := 0
+ n1 := 0
+ for _, i := range l {
+ n0 += (i + 1) % 2
+ n1 += i
+ if n0 > n/10 && n1 > n/10 {
+ return
+ }
+ }
+ t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1)
+}
+
+func BenchmarkSelectUncontended(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ myc1 := make(chan int, 1)
+ myc2 := make(chan int, 1)
+ myc1 <- 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ select {
+ case <-myc1:
+ myc2 <- 0
+ case <-myc2:
+ myc1 <- 0
+ }
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSelectContended(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ myc1 := make(chan int, procs)
+ myc2 := make(chan int, procs)
+ for p := 0; p < procs; p++ {
+ myc1 <- 0
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ select {
+ case <-myc1:
+ myc2 <- 0
+ case <-myc2:
+ myc1 <- 0
+ }
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSelectNonblock(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ myc1 := make(chan int)
+ myc2 := make(chan int)
+ myc3 := make(chan int, 1)
+ myc4 := make(chan int, 1)
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ select {
+ case <-myc1:
+ default:
+ }
+ select {
+ case myc2 <- 0:
+ default:
+ }
+ select {
+ case <-myc3:
+ default:
+ }
+ select {
+ case myc4 <- 0:
+ default:
+ }
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkChanUncontended(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ myc := make(chan int, CallsPerSched)
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ myc <- 0
+ }
+ for g := 0; g < CallsPerSched; g++ {
+ <-myc
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkChanContended(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ myc := make(chan int, procs*CallsPerSched)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ myc <- 0
+ }
+ for g := 0; g < CallsPerSched; g++ {
+ <-myc
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkChanSync(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := 2
+ N := int32(b.N / CallsPerSched / procs * procs)
+ c := make(chan bool, procs)
+ myc := make(chan int)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for {
+ i := atomic.AddInt32(&N, -1)
+ if i < 0 {
+ break
+ }
+ for g := 0; g < CallsPerSched; g++ {
+ if i%2 == 0 {
+ <-myc
+ myc <- 0
+ } else {
+ myc <- 0
+ <-myc
+ }
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, 2*procs)
+ myc := make(chan int, chanSize)
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ myc <- 1
+ }
+ }
+ myc <- 0
+ c <- foo == 42
+ }()
+ go func() {
+ foo := 0
+ for {
+ v := <-myc
+ if v == 0 {
+ break
+ }
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ <-c
+ }
+}
+
+func BenchmarkChanProdCons0(b *testing.B) {
+ benchmarkChanProdCons(b, 0, 0)
+}
+
+func BenchmarkChanProdCons10(b *testing.B) {
+ benchmarkChanProdCons(b, 10, 0)
+}
+
+func BenchmarkChanProdCons100(b *testing.B) {
+ benchmarkChanProdCons(b, 100, 0)
+}
+
+func BenchmarkChanProdConsWork0(b *testing.B) {
+ benchmarkChanProdCons(b, 0, 100)
+}
+
+func BenchmarkChanProdConsWork10(b *testing.B) {
+ benchmarkChanProdCons(b, 10, 100)
+}
+
+func BenchmarkChanProdConsWork100(b *testing.B) {
+ benchmarkChanProdCons(b, 100, 100)
+}
+
+func BenchmarkChanCreation(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ for g := 0; g < CallsPerSched; g++ {
+ myc := make(chan int, 1)
+ myc <- 0
+ <-myc
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
diff --git a/libgo/go/runtime/closure_test.go b/libgo/go/runtime/closure_test.go
new file mode 100644
index 00000000000..ea65fbd5f5d
--- /dev/null
+++ b/libgo/go/runtime/closure_test.go
@@ -0,0 +1,53 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package runtime_test
+
+import "testing"
+
+var s int
+
+func BenchmarkCallClosure(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ s += func(ii int) int { return 2 * ii }(i)
+ }
+}
+
+func BenchmarkCallClosure1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ j := i
+ s += func(ii int) int { return 2*ii + j }(i)
+ }
+}
+
+var ss *int
+
+func BenchmarkCallClosure2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ j := i
+ s += func() int {
+ ss = &j
+ return 2
+ }()
+ }
+}
+
+func addr1(x int) *int {
+ return func() *int { return &x }()
+}
+
+func BenchmarkCallClosure3(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ss = addr1(i)
+ }
+}
+
+func addr2() (x int, p *int) {
+ return 0, func() *int { return &x }()
+}
+
+func BenchmarkCallClosure4(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, ss = addr2()
+ }
+}
diff --git a/libgo/go/runtime/debug/stack.go b/libgo/go/runtime/debug/stack.go
index e5fae632b13..a533a5c3bf4 100644
--- a/libgo/go/runtime/debug/stack.go
+++ b/libgo/go/runtime/debug/stack.go
@@ -52,7 +52,7 @@ func stack() []byte {
if err != nil {
continue
}
- lines = bytes.Split(data, []byte{'\n'}, -1)
+ lines = bytes.Split(data, []byte{'\n'})
lastFile = file
}
line-- // in stack trace, lines are 1-indexed but our array is 0-indexed
diff --git a/libgo/go/runtime/debug/stack_test.go b/libgo/go/runtime/debug/stack_test.go
index f4bdc46244f..94293bb934b 100644
--- a/libgo/go/runtime/debug/stack_test.go
+++ b/libgo/go/runtime/debug/stack_test.go
@@ -23,7 +23,7 @@ func (t T) method() []byte {
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()
+ (*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)
@@ -35,12 +35,12 @@ func (t T) method() []byte {
*/
func TestStack(t *testing.T) {
b := T(0).method()
- lines := strings.Split(string(b), "\n", -1)
+ lines := strings.Split(string(b), "\n")
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[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")
diff --git a/libgo/go/runtime/error.go b/libgo/go/runtime/error.go
index 2515722aaa4..2b5517fbef5 100644
--- a/libgo/go/runtime/error.go
+++ b/libgo/go/runtime/error.go
@@ -131,3 +131,8 @@ func Printany(i interface{}) {
print("(", typestring(i), ") ", i)
}
}
+
+// called from generated code
+func panicwrap(pkg, typ, meth string) {
+ panic("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")
+}
diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go
index 58631c7b4b5..b3af22123e9 100644
--- a/libgo/go/runtime/export_test.go
+++ b/libgo/go/runtime/export_test.go
@@ -15,3 +15,13 @@ var F32to64 = f32to64
var Fcmp64 = fcmp64
var Fintto64 = fintto64
var F64toint = f64toint
+
+func entersyscall()
+func exitsyscall()
+
+/* Useless for gccgo.
+
+var Entersyscall = entersyscall
+var Exitsyscall = exitsyscall
+
+*/
diff --git a/libgo/go/runtime/mem.go b/libgo/go/runtime/mem.go
index 2fc1892a10b..3f213062910 100644
--- a/libgo/go/runtime/mem.go
+++ b/libgo/go/runtime/mem.go
@@ -52,7 +52,7 @@ type MemStatsType struct {
}
}
-var Sizeof_C_MStats int // filled in by malloc.goc
+var Sizeof_C_MStats uintptr // filled in by malloc.goc
func init() {
if Sizeof_C_MStats != unsafe.Sizeof(MemStats) {
@@ -62,8 +62,13 @@ func init() {
}
// MemStats holds statistics about the memory system.
-// The statistics are only approximate, as they are not interlocked on update.
+// The statistics may be out of date, as the information is
+// updated lazily from per-thread caches.
+// Use UpdateMemStats to bring the statistics up to date.
var MemStats MemStatsType
+// UpdateMemStats brings MemStats up to date.
+func UpdateMemStats()
+
// GC runs a garbage collection.
func GC()
diff --git a/libgo/go/runtime/pprof/pprof_test.go b/libgo/go/runtime/pprof/pprof_test.go
index a060917a280..4486d5525f7 100644
--- a/libgo/go/runtime/pprof/pprof_test.go
+++ b/libgo/go/runtime/pprof/pprof_test.go
@@ -43,7 +43,7 @@ func TestCPUProfile(t *testing.T) {
// Convert []byte to []uintptr.
bytes := prof.Bytes()
val := *(*[]uintptr)(unsafe.Pointer(&bytes))
- val = val[:len(bytes)/unsafe.Sizeof(uintptr(0))]
+ val = val[:len(bytes)/int(unsafe.Sizeof(uintptr(0)))]
if len(val) < 10 {
t.Fatalf("profile too short: %#x", val)
diff --git a/libgo/go/runtime/proc_test.go b/libgo/go/runtime/proc_test.go
index a15b2d80a4e..1d20a58a420 100644
--- a/libgo/go/runtime/proc_test.go
+++ b/libgo/go/runtime/proc_test.go
@@ -6,6 +6,7 @@ package runtime_test
import (
"runtime"
+ "sync/atomic"
"testing"
)
@@ -24,20 +25,105 @@ func TestStopTheWorldDeadlock(t *testing.T) {
t.Logf("skipping during short test")
return
}
- runtime.GOMAXPROCS(3)
- compl := make(chan int, 1)
+ maxprocs := runtime.GOMAXPROCS(3)
+ compl := make(chan bool, 2)
go func() {
for i := 0; i != 1000; i += 1 {
runtime.GC()
}
- compl <- 0
+ compl <- true
}()
go func() {
for i := 0; i != 1000; i += 1 {
runtime.GOMAXPROCS(3)
}
+ compl <- true
}()
go perpetuumMobile()
<-compl
+ <-compl
stop <- true
+ runtime.GOMAXPROCS(maxprocs)
+}
+
+func stackGrowthRecursive(i int) {
+ var pad [128]uint64
+ if i != 0 && pad[0] == 0 {
+ stackGrowthRecursive(i - 1)
+ }
+}
+
+func BenchmarkStackGrowth(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ stackGrowthRecursive(10)
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+/* These benchmarks are meaningless for gccgo.
+
+func BenchmarkSyscall(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ runtime.Entersyscall()
+ runtime.Exitsyscall()
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
}
+
+func BenchmarkSyscallWork(b *testing.B) {
+ const CallsPerSched = 1000
+ const LocalWork = 100
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 42
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ runtime.Entersyscall()
+ for i := 0; i < LocalWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ runtime.Exitsyscall()
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+*/
diff --git a/libgo/go/runtime/sema_test.go b/libgo/go/runtime/sema_test.go
new file mode 100644
index 00000000000..d95bb1ec58f
--- /dev/null
+++ b/libgo/go/runtime/sema_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 runtime_test
+
+import (
+ "runtime"
+ "sync/atomic"
+ "testing"
+)
+
+func BenchmarkSemaUncontended(b *testing.B) {
+ type PaddedSem struct {
+ sem uint32
+ pad [32]uint32
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ sem := new(PaddedSem)
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ runtime.Semrelease(&sem.sem)
+ runtime.Semacquire(&sem.sem)
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkSema(b *testing.B, block, work bool) {
+ const CallsPerSched = 1000
+ const LocalWork = 100
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ c2 := make(chan bool, procs/2)
+ sem := uint32(0)
+ if block {
+ for p := 0; p < procs/2; p++ {
+ go func() {
+ runtime.Semacquire(&sem)
+ c2 <- true
+ }()
+ }
+ }
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ runtime.Semrelease(&sem)
+ if work {
+ for i := 0; i < LocalWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ runtime.Semacquire(&sem)
+ }
+ }
+ c <- foo == 42
+ runtime.Semrelease(&sem)
+ }()
+ }
+ if block {
+ for p := 0; p < procs/2; p++ {
+ <-c2
+ }
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkSemaSyntNonblock(b *testing.B) {
+ benchmarkSema(b, false, false)
+}
+
+func BenchmarkSemaSyntBlock(b *testing.B) {
+ benchmarkSema(b, true, false)
+}
+
+func BenchmarkSemaWorkNonblock(b *testing.B) {
+ benchmarkSema(b, false, true)
+}
+
+func BenchmarkSemaWorkBlock(b *testing.B) {
+ benchmarkSema(b, true, true)
+}
diff --git a/libgo/go/runtime/softfloat64.go b/libgo/go/runtime/softfloat64.go
index d9bbe5def68..e0c3b7b738d 100644
--- a/libgo/go/runtime/softfloat64.go
+++ b/libgo/go/runtime/softfloat64.go
@@ -11,7 +11,7 @@ package runtime
const (
mantbits64 uint = 52
expbits64 uint = 11
- bias64 = -1<<(expbits64-1) + 1
+ bias64 = -1<<(expbits64-1) + 1
nan64 uint64 = (1<<expbits64-1)<<mantbits64 + 1
inf64 uint64 = (1<<expbits64 - 1) << mantbits64
@@ -19,7 +19,7 @@ const (
mantbits32 uint = 23
expbits32 uint = 8
- bias32 = -1<<(expbits32-1) + 1
+ bias32 = -1<<(expbits32-1) + 1
nan32 uint32 = (1<<expbits32-1)<<mantbits32 + 1
inf32 uint32 = (1<<expbits32 - 1) << mantbits32
diff --git a/libgo/go/runtime/symtab_test.go b/libgo/go/runtime/symtab_test.go
new file mode 100644
index 00000000000..0db63c347fd
--- /dev/null
+++ b/libgo/go/runtime/symtab_test.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 runtime_test
+
+import (
+ "runtime"
+ "strings"
+ "testing"
+)
+
+var _ = runtime.Caller
+var _ = strings.HasSuffix
+type _ testing.T
+
+/* runtime.Caller is not fully implemented for gccgo.
+
+func TestCaller(t *testing.T) {
+ procs := runtime.GOMAXPROCS(-1)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for i := 0; i < 1000; i++ {
+ testCallerFoo(t)
+ }
+ c <- true
+ }()
+ defer func() {
+ <-c
+ }()
+ }
+}
+
+func testCallerFoo(t *testing.T) {
+ testCallerBar(t)
+}
+
+func testCallerBar(t *testing.T) {
+ for i := 0; i < 2; i++ {
+ pc, file, line, ok := runtime.Caller(i)
+ f := runtime.FuncForPC(pc)
+ if !ok ||
+ !strings.HasSuffix(file, "symtab_test.go") ||
+ (i == 0 && !strings.HasSuffix(f.Name(), "testCallerBar")) ||
+ (i == 1 && !strings.HasSuffix(f.Name(), "testCallerFoo")) ||
+ line < 5 || line > 1000 ||
+ f.Entry() >= pc {
+ t.Errorf("incorrect symbol info %d: %t %d %d %s %s %d",
+ i, ok, f.Entry(), pc, f.Name(), file, line)
+ }
+ }
+}
+
+*/
diff --git a/libgo/go/scanner/scanner.go b/libgo/go/scanner/scanner.go
index e79d392f70c..8fbcb9c1155 100644
--- a/libgo/go/scanner/scanner.go
+++ b/libgo/go/scanner/scanner.go
@@ -34,7 +34,6 @@ import (
"utf8"
)
-
// TODO(gri): Consider changing this to use the new (token) Position package.
// A source position is represented by a Position value.
@@ -46,11 +45,9 @@ type Position struct {
Column int // column number, starting at 1 (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() {
@@ -65,7 +62,6 @@ func (pos Position) String() string {
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:
@@ -84,7 +80,6 @@ const (
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)
@@ -98,7 +93,6 @@ const (
skipComment
)
-
var tokenString = map[int]string{
EOF: "EOF",
Ident: "Ident",
@@ -110,7 +104,6 @@ var tokenString = map[int]string{
Comment: "Comment",
}
-
// TokenString returns a (visible) string for a token or Unicode character.
func TokenString(tok int) string {
if s, found := tokenString[tok]; found {
@@ -119,12 +112,10 @@ func TokenString(tok int) string {
return fmt.Sprintf("%q", string(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.
@@ -179,7 +170,6 @@ type Scanner struct {
Position
}
-
// Init initializes a Scanner with a new source and returns s.
// Error is set to nil, ErrorCount is set to 0, Mode is set to GoTokens,
// and Whitespace is set to GoWhitespace.
@@ -215,7 +205,6 @@ func (s *Scanner) Init(src io.Reader) *Scanner {
return s
}
-
// TODO(gri): The code for next() and the internal scanner state could benefit
// from a rethink. While next() is optimized for the common ASCII
// case, the "corrections" needed for proper position tracking undo
@@ -276,7 +265,12 @@ func (s *Scanner) next() int {
// uncommon case: not ASCII
ch, width = utf8.DecodeRune(s.srcBuf[s.srcPos:s.srcEnd])
if ch == utf8.RuneError && width == 1 {
+ // advance for correct error position
+ s.srcPos += width
+ s.lastCharLen = width
+ s.column++
s.error("illegal UTF-8 encoding")
+ return ch
}
}
}
@@ -300,7 +294,6 @@ func (s *Scanner) next() int {
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 not nil; otherwise
@@ -314,7 +307,6 @@ func (s *Scanner) Next() int {
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.
@@ -325,7 +317,6 @@ func (s *Scanner) Peek() int {
return s.ch
}
-
func (s *Scanner) error(msg string) {
s.ErrorCount++
if s.Error != nil {
@@ -335,7 +326,6 @@ func (s *Scanner) error(msg string) {
fmt.Fprintf(os.Stderr, "%s: %s\n", 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) {
@@ -344,7 +334,6 @@ func (s *Scanner) scanIdentifier() int {
return ch
}
-
func digitVal(ch int) int {
switch {
case '0' <= ch && ch <= '9':
@@ -357,10 +346,8 @@ func digitVal(ch int) int {
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()
@@ -368,7 +355,6 @@ func (s *Scanner) scanMantissa(ch int) int {
return ch
}
-
func (s *Scanner) scanFraction(ch int) int {
if ch == '.' {
ch = s.scanMantissa(s.next())
@@ -376,7 +362,6 @@ func (s *Scanner) scanFraction(ch int) int {
return ch
}
-
func (s *Scanner) scanExponent(ch int) int {
if ch == 'e' || ch == 'E' {
ch = s.next()
@@ -388,7 +373,6 @@ func (s *Scanner) scanExponent(ch int) int {
return ch
}
-
func (s *Scanner) scanNumber(ch int) (int, int) {
// isDecimal(ch)
if ch == '0' {
@@ -433,7 +417,6 @@ func (s *Scanner) scanNumber(ch int) (int, int) {
return Int, ch
}
-
func (s *Scanner) scanDigits(ch, base, n int) int {
for n > 0 && digitVal(ch) < base {
ch = s.next()
@@ -445,7 +428,6 @@ func (s *Scanner) scanDigits(ch, base, n int) int {
return ch
}
-
func (s *Scanner) scanEscape(quote int) int {
ch := s.next() // read character after '/'
switch ch {
@@ -466,7 +448,6 @@ func (s *Scanner) scanEscape(quote int) int {
return ch
}
-
func (s *Scanner) scanString(quote int) (n int) {
ch := s.next() // read character after quote
for ch != quote {
@@ -484,7 +465,6 @@ func (s *Scanner) scanString(quote int) (n int) {
return
}
-
func (s *Scanner) scanRawString() {
ch := s.next() // read character after '`'
for ch != '`' {
@@ -496,14 +476,12 @@ func (s *Scanner) scanRawString() {
}
}
-
func (s *Scanner) scanChar() {
if s.scanString('\'') != 1 {
s.error("illegal char literal")
}
}
-
func (s *Scanner) scanComment(ch int) int {
// ch == '/' || ch == '*'
if ch == '/' {
@@ -532,7 +510,6 @@ func (s *Scanner) scanComment(ch int) int {
return ch
}
-
// 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
@@ -635,7 +612,6 @@ redo:
return tok
}
-
// Pos returns the position of the character immediately after
// the character or token returned by the last call to Next or Scan.
func (s *Scanner) Pos() (pos Position) {
@@ -658,7 +634,6 @@ func (s *Scanner) Pos() (pos Position) {
return
}
-
// TokenText returns the string corresponding to the most recently scanned token.
// Valid after calling Scan().
func (s *Scanner) TokenText() string {
diff --git a/libgo/go/scanner/scanner_test.go b/libgo/go/scanner/scanner_test.go
index cf9ad01111f..8403d615354 100644
--- a/libgo/go/scanner/scanner_test.go
+++ b/libgo/go/scanner/scanner_test.go
@@ -13,14 +13,12 @@ import (
"utf8"
)
-
// 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]
@@ -32,7 +30,6 @@ func (r *StringReader) Read(p []byte) (n int, err os.Error) {
return
}
-
func readRuneSegments(t *testing.T, segments []string) {
got := ""
want := strings.Join(segments, "")
@@ -49,7 +46,6 @@ func readRuneSegments(t *testing.T, segments []string) {
}
}
-
var segmentList = [][]string{
{},
{""},
@@ -61,14 +57,12 @@ var segmentList = [][]string{
{"Hello", ", ", "", "World", "!"},
}
-
func TestNext(t *testing.T) {
for _, s := range segmentList {
readRuneSegments(t, s)
}
}
-
type token struct {
tok int
text string
@@ -234,7 +228,6 @@ var tokenList = []token{
{'(', "("},
}
-
func makeSource(pattern string) *bytes.Buffer {
var buf bytes.Buffer
for _, k := range tokenList {
@@ -243,7 +236,6 @@ func makeSource(pattern string) *bytes.Buffer {
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)
@@ -263,7 +255,6 @@ func checkTok(t *testing.T, s *Scanner, line, got, want int, text string) {
}
}
-
func countNewlines(s string) int {
n := 0
for _, ch := range s {
@@ -274,7 +265,6 @@ func countNewlines(s string) int {
return n
}
-
func testScan(t *testing.T, mode uint) {
s := new(Scanner).Init(makeSource(" \t%s\n"))
s.Mode = mode
@@ -290,13 +280,11 @@ func testScan(t *testing.T, mode uint) {
checkTok(t, s, line, tok, EOF, "")
}
-
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)
@@ -323,7 +311,6 @@ func TestPosition(t *testing.T) {
}
}
-
func TestScanZeroMode(t *testing.T) {
src := makeSource("%s\n")
str := src.String()
@@ -345,7 +332,6 @@ func TestScanZeroMode(t *testing.T) {
}
}
-
func testScanSelectedMode(t *testing.T, mode uint, class int) {
src := makeSource("%s\n")
s := new(Scanner).Init(src)
@@ -362,7 +348,6 @@ func testScanSelectedMode(t *testing.T, mode uint, class int) {
}
}
-
func TestScanSelectedMask(t *testing.T) {
testScanSelectedMode(t, 0, 0)
testScanSelectedMode(t, ScanIdents, Ident)
@@ -375,7 +360,6 @@ func TestScanSelectedMask(t *testing.T) {
testScanSelectedMode(t, ScanComments, Comment)
}
-
func TestScanNext(t *testing.T) {
s := new(Scanner).Init(bytes.NewBufferString("if a == bcd /* comment */ {\n\ta += c\n} // line comment ending in eof"))
checkTok(t, s, 1, s.Scan(), Ident, "if")
@@ -397,7 +381,6 @@ func TestScanNext(t *testing.T) {
}
}
-
func TestScanWhitespace(t *testing.T) {
var buf bytes.Buffer
var ws uint64
@@ -418,13 +401,15 @@ func TestScanWhitespace(t *testing.T) {
}
}
-
-func testError(t *testing.T, src, msg string, tok int) {
+func testError(t *testing.T, src, pos, msg string, tok int) {
s := new(Scanner).Init(bytes.NewBufferString(src))
errorCalled := false
- s.Error = func(_ *Scanner, m string) {
+ s.Error = func(s *Scanner, m string) {
if !errorCalled {
// only look at first error
+ if p := s.Pos().String(); p != pos {
+ t.Errorf("pos = %q, want %q for %q", p, pos, src)
+ }
if m != msg {
t.Errorf("msg = %q, want %q for %q", m, msg, src)
}
@@ -443,23 +428,37 @@ func testError(t *testing.T, src, msg string, tok int) {
}
}
-
func TestError(t *testing.T) {
- testError(t, "\x00", "illegal character NUL", 0)
- testError(t, "\xff", "illegal UTF-8 encoding", utf8.RuneError)
- 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, `"abc`+"\x00"+`def"`, "illegal character NUL", String)
- testError(t, `"abc`+"\xff"+`def"`, "illegal UTF-8 encoding", String)
+ testError(t, "\x00", "1:1", "illegal character NUL", 0)
+ testError(t, "\x80", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
+ testError(t, "\xff", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
+
+ testError(t, "a\x00", "1:2", "illegal character NUL", Ident)
+ testError(t, "ab\x80", "1:3", "illegal UTF-8 encoding", Ident)
+ testError(t, "abc\xff", "1:4", "illegal UTF-8 encoding", Ident)
+
+ testError(t, `"a`+"\x00", "1:3", "illegal character NUL", String)
+ testError(t, `"ab`+"\x80", "1:4", "illegal UTF-8 encoding", String)
+ testError(t, `"abc`+"\xff", "1:5", "illegal UTF-8 encoding", String)
+
+ testError(t, "`a"+"\x00", "1:3", "illegal character NUL", String)
+ testError(t, "`ab"+"\x80", "1:4", "illegal UTF-8 encoding", String)
+ testError(t, "`abc"+"\xff", "1:5", "illegal UTF-8 encoding", String)
+
+ testError(t, `'\"'`, "1:3", "illegal char escape", Char)
+ testError(t, `"\'"`, "1:3", "illegal char escape", String)
+
+ testError(t, `01238`, "1:6", "illegal octal number", Int)
+ testError(t, `'aa'`, "1:4", "illegal char literal", Char)
+
+ testError(t, `'`, "1:2", "literal not terminated", Char)
+ testError(t, `'`+"\n", "1:2", "literal not terminated", Char)
+ testError(t, `"abc`, "1:5", "literal not terminated", String)
+ testError(t, `"abc`+"\n", "1:5", "literal not terminated", String)
+ testError(t, "`abc\n", "2:1", "literal not terminated", String)
+ testError(t, `/*/`, "1:4", "comment not terminated", EOF)
}
-
func checkPos(t *testing.T, got, want Position) {
if got.Offset != want.Offset || got.Line != want.Line || got.Column != want.Column {
t.Errorf("got offset, line, column = %d, %d, %d; want %d, %d, %d",
@@ -467,7 +466,6 @@ func checkPos(t *testing.T, got, want Position) {
}
}
-
func checkNextPos(t *testing.T, s *Scanner, offset, line, column, char int) {
if ch := s.Next(); ch != char {
t.Errorf("ch = %s, want %s", TokenString(ch), TokenString(char))
@@ -476,7 +474,6 @@ func checkNextPos(t *testing.T, s *Scanner, offset, line, column, char int) {
checkPos(t, s.Pos(), want)
}
-
func checkScanPos(t *testing.T, s *Scanner, offset, line, column, char int) {
want := Position{Offset: offset, Line: line, Column: column}
checkPos(t, s.Pos(), want)
@@ -489,7 +486,6 @@ func checkScanPos(t *testing.T, s *Scanner, offset, line, column, char int) {
checkPos(t, s.Position, want)
}
-
func TestPos(t *testing.T) {
// corner case: empty source
s := new(Scanner).Init(bytes.NewBufferString(""))
diff --git a/libgo/go/smtp/smtp.go b/libgo/go/smtp/smtp.go
index 3f89af14720..2d5e8624713 100644
--- a/libgo/go/smtp/smtp.go
+++ b/libgo/go/smtp/smtp.go
@@ -93,11 +93,11 @@ func (c *Client) ehlo() os.Error {
return err
}
ext := make(map[string]string)
- extList := strings.Split(msg, "\n", -1)
+ extList := strings.Split(msg, "\n")
if len(extList) > 1 {
extList = extList[1:]
for _, line := range extList {
- args := strings.Split(line, " ", 2)
+ args := strings.SplitN(line, " ", 2)
if len(args) > 1 {
ext[args[0]] = args[1]
} else {
@@ -106,7 +106,7 @@ func (c *Client) ehlo() os.Error {
}
}
if mechs, ok := ext["AUTH"]; ok {
- c.auth = strings.Split(mechs, " ", -1)
+ c.auth = strings.Split(mechs, " ")
}
c.ext = ext
return err
@@ -151,8 +151,7 @@ func (c *Client) Auth(a Auth) os.Error {
var msg []byte
switch code {
case 334:
- msg = make([]byte, encoding.DecodedLen(len(msg64)))
- _, err = encoding.Decode(msg, []byte(msg64))
+ msg, err = encoding.DecodeString(msg64)
case 235:
// the last message isn't base64 because it isn't a challenge
msg = []byte(msg64)
diff --git a/libgo/go/smtp/smtp_test.go b/libgo/go/smtp/smtp_test.go
index 49363adf0a9..c053557d7f4 100644
--- a/libgo/go/smtp/smtp_test.go
+++ b/libgo/go/smtp/smtp_test.go
@@ -64,8 +64,8 @@ func (f faker) Close() os.Error {
}
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")
+ basicServer = strings.Join(strings.Split(basicServer, "\n"), "\r\n")
+ basicClient = strings.Join(strings.Split(basicClient, "\n"), "\r\n")
var cmdbuf bytes.Buffer
bcmdbuf := bufio.NewWriter(&cmdbuf)
diff --git a/libgo/go/sort/search.go b/libgo/go/sort/search.go
index 6828e19b63b..4f0ce55c3c5 100644
--- a/libgo/go/sort/search.go
+++ b/libgo/go/sort/search.go
@@ -15,7 +15,7 @@ package sort
// Search calls f(i) only for i in the range [0, n).
//
// A common use of Search is to find the index i for a value x in
-// a sorted, indexable data structure like an array or slice.
+// a sorted, indexable data structure such as an array or slice.
// In this case, the argument f, typically a closure, captures the value
// to be searched for, and how the data structure is indexed and
// ordered.
@@ -71,40 +71,34 @@ func Search(n int, f func(int) bool) int {
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.
+// as specified by Search. The slice must be sorted in ascending order.
//
func SearchInts(a []int, x int) int {
return Search(len(a), func(i int) bool { return a[i] >= x })
}
-
// SearchFloat64s searches for x in a sorted slice of float64s and returns the index
-// as specified by Search. The array must be sorted in ascending order.
+// as specified by Search. The slice must be sorted in ascending order.
//
func SearchFloat64s(a []float64, x float64) int {
return Search(len(a), func(i int) bool { return a[i] >= x })
}
-
-// SearchStrings searches for x in a sorted slice of strings and returns the index
-// as specified by Search. The array must be sorted in ascending order.
+// SearchStrings searches for x slice a sorted slice of strings and returns the index
+// as specified by Search. The slice must be sorted in ascending order.
//
func SearchStrings(a []string, x string) int {
return Search(len(a), func(i int) bool { return a[i] >= x })
}
-
// Search returns the result of applying SearchInts to the receiver and x.
-func (p IntArray) Search(x int) int { return SearchInts(p, x) }
-
+func (p IntSlice) Search(x int) int { return SearchInts(p, x) }
// Search returns the result of applying SearchFloat64s to the receiver and x.
-func (p Float64Array) Search(x float64) int { return SearchFloat64s(p, x) }
-
+func (p Float64Slice) Search(x float64) int { return SearchFloat64s(p, x) }
// Search returns the result of applying SearchStrings to the receiver and x.
-func (p StringArray) Search(x string) int { return SearchStrings(p, x) }
+func (p StringSlice) Search(x string) int { return SearchStrings(p, x) }
diff --git a/libgo/go/sort/search_test.go b/libgo/go/sort/search_test.go
index 939f66af380..07295ffa976 100644
--- a/libgo/go/sort/search_test.go
+++ b/libgo/go/sort/search_test.go
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package sort
-
-import "testing"
+package sort_test
+import (
+ . "sort"
+ "testing"
+)
func f(a []int, x int) func(int) bool {
return func(i int) bool {
@@ -13,7 +15,6 @@ func f(a []int, x int) func(int) bool {
}
}
-
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 {
@@ -46,7 +47,6 @@ var tests = []struct {
{"overflow", 2e9, func(i int) bool { return false }, 2e9},
}
-
func TestSearch(t *testing.T) {
for _, e := range tests {
i := Search(e.n, e.f)
@@ -56,7 +56,6 @@ func TestSearch(t *testing.T) {
}
}
-
// 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.)
//
@@ -70,7 +69,6 @@ func log2(x int) int {
return n
}
-
func TestSearchEfficiency(t *testing.T) {
n := 100
step := 1
@@ -93,7 +91,6 @@ func TestSearchEfficiency(t *testing.T) {
}
}
-
// Smoke tests for convenience wrappers - not comprehensive.
var fdata = []float64{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7}
@@ -107,12 +104,11 @@ var wrappertests = []struct {
{"SearchInts", SearchInts(data, 11), 8},
{"SearchFloat64s", SearchFloat64s(fdata, 2.1), 4},
{"SearchStrings", SearchStrings(sdata, ""), 0},
- {"IntArray.Search", IntArray(data).Search(0), 2},
- {"Float64Array.Search", Float64Array(fdata).Search(2.0), 3},
- {"StringArray.Search", StringArray(sdata).Search("x"), 3},
+ {"IntSlice.Search", IntSlice(data).Search(0), 2},
+ {"Float64Slice.Search", Float64Slice(fdata).Search(2.0), 3},
+ {"StringSlice.Search", StringSlice(sdata).Search("x"), 3},
}
-
func TestSearchWrappers(t *testing.T) {
for _, e := range wrappertests {
if e.result != e.i {
@@ -121,7 +117,6 @@ func TestSearchWrappers(t *testing.T) {
}
}
-
// Abstract exhaustive test: all sizes up to 100,
// all possible return values. If there are any small
// corner cases, this test exercises them.
diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go
index 30b1819af2d..0a4a4375f05 100644
--- a/libgo/go/sort/sort.go
+++ b/libgo/go/sort/sort.go
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package sort provides primitives for sorting arrays and user-defined
+// Package sort provides primitives for sorting slices and user-defined
// collections.
package sort
+import "math"
+
// 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.
@@ -82,7 +84,7 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
// data[d <= i < hi] = pivot
//
// Once b meets c, can swap the "= pivot" sections
- // into the middle of the array.
+ // into the middle of the slice.
pivot := lo
a, b, c, d := lo+1, lo+1, hi, hi
for b < c {
@@ -141,7 +143,6 @@ func quickSort(data Interface, a, b int) {
func Sort(data Interface) { quickSort(data, 0, data.Len()) }
-
func IsSorted(data Interface) bool {
n := data.Len()
for i := n - 1; i > 0; i-- {
@@ -152,55 +153,50 @@ func IsSorted(data Interface) bool {
return true
}
-
// Convenience types for common cases
-// IntArray attaches the methods of Interface to []int, sorting in increasing order.
-type IntArray []int
+// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
+type IntSlice []int
-func (p IntArray) Len() int { return len(p) }
-func (p IntArray) Less(i, j int) bool { return p[i] < p[j] }
-func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p IntSlice) Len() int { return len(p) }
+func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Sort is a convenience method.
-func (p IntArray) Sort() { Sort(p) }
-
+func (p IntSlice) Sort() { Sort(p) }
-// Float64Array attaches the methods of Interface to []float64, sorting in increasing order.
-type Float64Array []float64
+// Float64Slice attaches the methods of Interface to []float64, sorting in increasing order.
+type Float64Slice []float64
-func (p Float64Array) Len() int { return len(p) }
-func (p Float64Array) Less(i, j int) bool { return p[i] < p[j] }
-func (p Float64Array) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p Float64Slice) Len() int { return len(p) }
+func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || math.IsNaN(p[i]) && !math.IsNaN(p[j]) }
+func (p Float64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Sort is a convenience method.
-func (p Float64Array) Sort() { Sort(p) }
+func (p Float64Slice) Sort() { Sort(p) }
+// StringSlice attaches the methods of Interface to []string, sorting in increasing order.
+type StringSlice []string
-// 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] }
+func (p StringSlice) Len() int { return len(p) }
+func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p StringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Sort is a convenience method.
-func (p StringArray) Sort() { Sort(p) }
-
+func (p StringSlice) Sort() { Sort(p) }
// Convenience wrappers for common cases
-// SortInts sorts an array of ints in increasing order.
-func SortInts(a []int) { Sort(IntArray(a)) }
-// SortFloat64s sorts an array of float64s in increasing order.
-func SortFloat64s(a []float64) { Sort(Float64Array(a)) }
-// SortStrings sorts an array of strings in increasing order.
-func SortStrings(a []string) { Sort(StringArray(a)) }
-
-
-// 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)) }
+// Ints sorts a slice of ints in increasing order.
+func Ints(a []int) { Sort(IntSlice(a)) }
+// Float64s sorts a slice of float64s in increasing order.
+func Float64s(a []float64) { Sort(Float64Slice(a)) }
+// Strings sorts a slice of strings in increasing order.
+func Strings(a []string) { Sort(StringSlice(a)) }
+
+// IntsAreSorted tests whether a slice of ints is sorted in increasing order.
+func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }
+// Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
+func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }
+// StringsAreSorted tests whether a slice of strings is sorted in increasing order.
+func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
diff --git a/libgo/go/sort/sort_test.go b/libgo/go/sort/sort_test.go
index 3d7337fd010..5007a92a562 100644
--- a/libgo/go/sort/sort_test.go
+++ b/libgo/go/sort/sort_test.go
@@ -2,23 +2,24 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package sort
+package sort_test
import (
"fmt"
+ "math"
"rand"
+ . "sort"
"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 float64s = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8}
var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
-func TestSortIntArray(t *testing.T) {
+func TestSortIntSlice(t *testing.T) {
data := ints
- a := IntArray(data[0:])
+ a := IntSlice(data[0:])
Sort(a)
if !IsSorted(a) {
t.Errorf("sorted %v", ints)
@@ -26,9 +27,9 @@ func TestSortIntArray(t *testing.T) {
}
}
-func TestSortFloat64Array(t *testing.T) {
+func TestSortFloat64Slice(t *testing.T) {
data := float64s
- a := Float64Array(data[0:])
+ a := Float64Slice(data[0:])
Sort(a)
if !IsSorted(a) {
t.Errorf("sorted %v", float64s)
@@ -36,9 +37,9 @@ func TestSortFloat64Array(t *testing.T) {
}
}
-func TestSortStringArray(t *testing.T) {
+func TestSortStringSlice(t *testing.T) {
data := strings
- a := StringArray(data[0:])
+ a := StringSlice(data[0:])
Sort(a)
if !IsSorted(a) {
t.Errorf("sorted %v", strings)
@@ -46,27 +47,27 @@ func TestSortStringArray(t *testing.T) {
}
}
-func TestSortInts(t *testing.T) {
+func TestInts(t *testing.T) {
data := ints
- SortInts(data[0:])
+ Ints(data[0:])
if !IntsAreSorted(data[0:]) {
t.Errorf("sorted %v", ints)
t.Errorf(" got %v", data)
}
}
-func TestSortFloat64s(t *testing.T) {
+func TestFloat64s(t *testing.T) {
data := float64s
- SortFloat64s(data[0:])
+ Float64s(data[0:])
if !Float64sAreSorted(data[0:]) {
t.Errorf("sorted %v", float64s)
t.Errorf(" got %v", data)
}
}
-func TestSortStrings(t *testing.T) {
+func TestStrings(t *testing.T) {
data := strings
- SortStrings(data[0:])
+ Strings(data[0:])
if !StringsAreSorted(data[0:]) {
t.Errorf("sorted %v", strings)
t.Errorf(" got %v", data)
@@ -85,7 +86,7 @@ func TestSortLarge_Random(t *testing.T) {
if IntsAreSorted(data) {
t.Fatalf("terrible rand.rand")
}
- SortInts(data)
+ Ints(data)
if !IntsAreSorted(data) {
t.Errorf("sort didn't sort - 1M ints")
}
@@ -99,7 +100,7 @@ func BenchmarkSortString1K(b *testing.B) {
data[i] = strconv.Itoa(i ^ 0x2cc)
}
b.StartTimer()
- SortStrings(data)
+ Strings(data)
b.StopTimer()
}
}
@@ -112,7 +113,7 @@ func BenchmarkSortInt1K(b *testing.B) {
data[i] = i ^ 0x2cc
}
b.StartTimer()
- SortInts(data)
+ Ints(data)
b.StopTimer()
}
}
@@ -125,7 +126,7 @@ func BenchmarkSortInt64K(b *testing.B) {
data[i] = i ^ 0xcccc
}
b.StartTimer()
- SortInts(data)
+ Ints(data)
b.StopTimer()
}
}
@@ -161,7 +162,7 @@ func (d *testingData) Len() int { return len(d.data) }
func (d *testingData) Less(i, j int) bool { return d.data[i] < d.data[j] }
func (d *testingData) Swap(i, j int) {
if d.nswap >= d.maxswap {
- d.t.Errorf("%s: used %d swaps sorting array of %d", d.desc, d.nswap, len(d.data))
+ d.t.Errorf("%s: used %d swaps sorting slice of %d", d.desc, d.nswap, len(d.data))
d.t.FailNow()
}
d.nswap++
@@ -241,9 +242,9 @@ func TestBentleyMcIlroy(t *testing.T) {
for i := 0; i < n; i++ {
mdata[i] = data[i]
}
- // SortInts is known to be correct
+ // Ints is known to be correct
// because mode Sort runs after mode _Copy.
- SortInts(mdata)
+ Ints(mdata)
case _Dither:
for i := 0; i < n; i++ {
mdata[i] = data[i] + i%5
@@ -255,13 +256,13 @@ func TestBentleyMcIlroy(t *testing.T) {
Sort(d)
// If we were testing C qsort, we'd have to make a copy
- // of the array and sort it ourselves and then compare
+ // of the slice and sort it ourselves and then compare
// x against it, to ensure that qsort was only permuting
// the data, not (for example) overwriting it with zeros.
//
// In go, we don't have to be so paranoid: since the only
// mutating method Sort can call is TestingData.swap,
- // it suffices here just to check that the final array is sorted.
+ // it suffices here just to check that the final slice is sorted.
if !IntsAreSorted(mdata) {
t.Errorf("%s: ints not sorted", desc)
t.Errorf("\t%v", mdata)
@@ -272,3 +273,10 @@ func TestBentleyMcIlroy(t *testing.T) {
}
}
}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
diff --git a/libgo/go/strconv/atob.go b/libgo/go/strconv/atob.go
index 69fa2292a18..98ce750798d 100644
--- a/libgo/go/strconv/atob.go
+++ b/libgo/go/strconv/atob.go
@@ -7,8 +7,8 @@ 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.
+// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, 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":
diff --git a/libgo/go/strconv/atob_test.go b/libgo/go/strconv/atob_test.go
index 497df5b18d8..541e60d1e9e 100644
--- a/libgo/go/strconv/atob_test.go
+++ b/libgo/go/strconv/atob_test.go
@@ -24,11 +24,13 @@ var atobtests = []atobTest{
{"F", false, nil},
{"FALSE", false, nil},
{"false", false, nil},
+ {"False", false, nil},
{"1", true, nil},
{"t", true, nil},
{"T", true, nil},
{"TRUE", true, nil},
{"true", true, nil},
+ {"True", true, nil},
}
func TestAtob(t *testing.T) {
diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go
index a91e8bfa4aa..38b38053ce0 100644
--- a/libgo/go/strconv/atof.go
+++ b/libgo/go/strconv/atof.go
@@ -43,11 +43,13 @@ func special(s string) (f float64, ok bool) {
switch {
case equalIgnoreCase(s, "nan"):
return math.NaN(), true
- case equalIgnoreCase(s, "-inf"):
+ case equalIgnoreCase(s, "-inf"),
+ equalIgnoreCase(s, "-infinity"):
return math.Inf(-1), true
- case equalIgnoreCase(s, "+inf"):
- return math.Inf(1), true
- case equalIgnoreCase(s, "inf"):
+ case equalIgnoreCase(s, "+inf"),
+ equalIgnoreCase(s, "+infinity"),
+ equalIgnoreCase(s, "inf"),
+ equalIgnoreCase(s, "infinity"):
return math.Inf(1), true
}
return
diff --git a/libgo/go/strconv/atof_test.go b/libgo/go/strconv/atof_test.go
index 6d8396ee73b..0fdd0ea982b 100644
--- a/libgo/go/strconv/atof_test.go
+++ b/libgo/go/strconv/atof_test.go
@@ -47,6 +47,9 @@ var atoftests = []atofTest{
{"inf", "+Inf", nil},
{"-Inf", "-Inf", nil},
{"+INF", "+Inf", nil},
+ {"-Infinity", "-Inf", nil},
+ {"+INFINITY", "+Inf", nil},
+ {"Infinity", "+Inf", nil},
// largest float64
{"1.7976931348623157e308", "1.7976931348623157e+308", nil},
diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go
index f7b8456725b..58459421623 100644
--- a/libgo/go/strconv/atoi.go
+++ b/libgo/go/strconv/atoi.go
@@ -13,7 +13,6 @@ type NumError struct {
func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() }
-
func computeIntsize() uint {
siz := uint(8)
for 1<<siz != 0 {
@@ -42,6 +41,8 @@ func cutoff64(base int) uint64 {
// digits, err.Error = os.EINVAL; if the value corresponding
// to s cannot be represented by a uint64, err.Error = os.ERANGE.
func Btoui64(s string, b int) (n uint64, err os.Error) {
+ var cutoff uint64
+
s0 := s
switch {
case len(s) < 1:
@@ -68,12 +69,12 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
}
default:
- err = os.ErrorString("invalid base " + Itoa(b))
+ err = os.NewError("invalid base " + Itoa(b))
goto Error
}
n = 0
- cutoff := cutoff64(b)
+ cutoff = cutoff64(b)
for i := 0; i < len(s); i++ {
var v byte
@@ -171,7 +172,6 @@ func Btoi64(s string, base int) (i int64, err os.Error) {
// 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)
diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go
index 3a5cf1ba685..783065bfbf2 100644
--- a/libgo/go/strconv/decimal.go
+++ b/libgo/go/strconv/decimal.go
@@ -108,7 +108,7 @@ func newDecimal(i uint64) *decimal {
}
// 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.
+// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
const maxShift = 27
// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow.
diff --git a/libgo/go/strconv/fp_test.go b/libgo/go/strconv/fp_test.go
index 34baeee39b3..3096957f5d3 100644
--- a/libgo/go/strconv/fp_test.go
+++ b/libgo/go/strconv/fp_test.go
@@ -28,7 +28,7 @@ func pow2(i int) float64 {
// 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)
+ a := strings.SplitN(s, "p", 2)
if len(a) == 2 {
n, err := strconv.Atoi64(a[0])
if err != nil {
@@ -72,7 +72,7 @@ func myatof64(s string) (f float64, ok bool) {
// 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)
+ a := strings.SplitN(s, "p", 2)
if len(a) == 2 {
n, err := strconv.Atoi(a[0])
if err != nil {
@@ -116,7 +116,7 @@ func TestFp(t *testing.T) {
if len(line) == 0 || line[0] == '#' {
continue
}
- a := strings.Split(line, " ", -1)
+ a := strings.Split(line, " ")
if len(a) != 4 {
t.Error("testfp.txt:", lineno, ": wrong field count")
continue
diff --git a/libgo/go/strconv/quote.go b/libgo/go/strconv/quote.go
index ed588972363..05e49d32ddf 100644
--- a/libgo/go/strconv/quote.go
+++ b/libgo/go/strconv/quote.go
@@ -14,63 +14,109 @@ import (
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 {
+func quoteWith(s string, quote byte, ASCIIonly bool) 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.WriteByte(quote)
+ for width := 0; len(s) > 0; s = s[width:] {
+ rune := int(s[0])
+ width = 1
+ if rune >= utf8.RuneSelf {
+ rune, width = utf8.DecodeRuneInString(s)
+ }
+ if width == 1 && rune == utf8.RuneError {
+ buf.WriteString(`\x`)
+ buf.WriteByte(lowerhex[s[0]>>4])
+ buf.WriteByte(lowerhex[s[0]&0xF])
+ continue
+ }
+ if rune == int(quote) || rune == '\\' { // always backslashed
+ buf.WriteByte('\\')
+ buf.WriteByte(byte(rune))
+ continue
+ }
+ if ASCIIonly {
+ if rune <= unicode.MaxASCII && unicode.IsPrint(rune) {
+ buf.WriteRune(rune)
+ continue
+ }
+ } else if unicode.IsPrint(rune) {
+ buf.WriteRune(rune)
+ continue
+ }
+ switch rune {
+ case '\a':
buf.WriteString(`\a`)
- case c == '\b':
+ case '\b':
buf.WriteString(`\b`)
- case c == '\f':
+ case '\f':
buf.WriteString(`\f`)
- case c == '\n':
+ case '\n':
buf.WriteString(`\n`)
- case c == '\r':
+ case '\r':
buf.WriteString(`\r`)
- case c == '\t':
+ case '\t':
buf.WriteString(`\t`)
- case c == '\v':
+ case '\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 {
+ default:
+ switch {
+ case rune < ' ':
+ buf.WriteString(`\x`)
+ buf.WriteByte(lowerhex[s[0]>>4])
+ buf.WriteByte(lowerhex[s[0]&0xF])
+ case rune > unicode.MaxRune:
+ rune = 0xFFFD
+ fallthrough
+ case rune < 0x10000:
buf.WriteString(`\u`)
- for j := uint(0); j < 4; j++ {
- buf.WriteByte(lowerhex[(r>>(12-4*j))&0xF])
+ for s := 12; s >= 0; s -= 4 {
+ buf.WriteByte(lowerhex[rune>>uint(s)&0xF])
}
- } else {
+ default:
buf.WriteString(`\U`)
- for j := uint(0); j < 8; j++ {
- buf.WriteByte(lowerhex[(r>>(28-4*j))&0xF])
+ for s := 28; s >= 0; s -= 4 {
+ buf.WriteByte(lowerhex[rune>>uint(s)&0xF])
}
}
-
- default:
- EscX:
- buf.WriteString(`\x`)
- buf.WriteByte(lowerhex[c>>4])
- buf.WriteByte(lowerhex[c&0xF])
}
}
- buf.WriteByte('"')
+ buf.WriteByte(quote)
return buf.String()
+
+}
+
+// Quote returns a double-quoted Go string literal representing s. The
+// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
+// control characters and non-printable characters as defined by
+// unicode.IsPrint.
+func Quote(s string) string {
+ return quoteWith(s, '"', false)
+}
+
+// QuoteToASCII returns a double-quoted Go string literal representing s.
+// The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
+// non-ASCII characters and non-printable characters as defined by
+// unicode.IsPrint.
+func QuoteToASCII(s string) string {
+ return quoteWith(s, '"', true)
+}
+
+// QuoteRune returns a single-quoted Go character literal representing the
+// rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
+// for control characters and non-printable characters as defined by
+// unicode.IsPrint.
+func QuoteRune(rune int) string {
+ // TODO: avoid the allocation here.
+ return quoteWith(string(rune), '\'', false)
+}
+
+// QuoteRuneToASCII returns a single-quoted Go character literal representing
+// the rune. The returned string uses Go escape sequences (\t, \n, \xFF,
+// \u0100) for non-ASCII characters and non-printable characters as defined
+// by unicode.IsPrint.
+func QuoteRuneToASCII(rune int) string {
+ // TODO: avoid the allocation here.
+ return quoteWith(string(rune), '\'', true)
}
// CanBackquote returns whether the string s would be
diff --git a/libgo/go/strconv/quote_test.go b/libgo/go/strconv/quote_test.go
index 1235fcb9aef..4d615db443a 100644
--- a/libgo/go/strconv/quote_test.go
+++ b/libgo/go/strconv/quote_test.go
@@ -11,28 +11,70 @@ import (
)
type quoteTest struct {
- in string
- out string
+ in string
+ out string
+ ascii 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"`},
+ {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`},
+ {"\\", `"\\"`, `"\\"`},
+ {"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`},
+ {"\u263a", `"☺"`, `"\u263a"`},
+ {"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`},
+ {"\x04", `"\x04"`, `"\x04"`},
}
func TestQuote(t *testing.T) {
- for i := 0; i < len(quotetests); i++ {
- tt := quotetests[i]
+ for _, tt := range quotetests {
if out := Quote(tt.in); out != tt.out {
t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out)
}
}
}
+func TestQuoteToASCII(t *testing.T) {
+ for _, tt := range quotetests {
+ if out := QuoteToASCII(tt.in); out != tt.ascii {
+ t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii)
+ }
+ }
+}
+
+type quoteRuneTest struct {
+ in int
+ out string
+ ascii string
+}
+
+var quoterunetests = []quoteRuneTest{
+ {'a', `'a'`, `'a'`},
+ {'\a', `'\a'`, `'\a'`},
+ {'\\', `'\\'`, `'\\'`},
+ {0xFF, `'ÿ'`, `'\u00ff'`},
+ {0x263a, `'☺'`, `'\u263a'`},
+ {0xfffd, `'�'`, `'\ufffd'`},
+ {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`},
+ {0x0010ffff + 1, `'�'`, `'\ufffd'`},
+ {0x04, `'\x04'`, `'\x04'`},
+}
+
+func TestQuoteRune(t *testing.T) {
+ for _, tt := range quoterunetests {
+ if out := QuoteRune(tt.in); out != tt.out {
+ t.Errorf("QuoteRune(%U) = %s, want %s", tt.in, out, tt.out)
+ }
+ }
+}
+
+func TestQuoteRuneToASCII(t *testing.T) {
+ for _, tt := range quoterunetests {
+ if out := QuoteRuneToASCII(tt.in); out != tt.ascii {
+ t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii)
+ }
+ }
+}
+
type canBackquoteTest struct {
in string
out bool
@@ -80,15 +122,19 @@ var canbackquotetests = []canBackquoteTest{
}
func TestCanBackquote(t *testing.T) {
- for i := 0; i < len(canbackquotetests); i++ {
- tt := canbackquotetests[i]
+ for _, tt := range canbackquotetests {
if out := CanBackquote(tt.in); out != tt.out {
t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out)
}
}
}
-var unquotetests = []quoteTest{
+type unQuoteTest struct {
+ in string
+ out string
+}
+
+var unquotetests = []unQuoteTest{
{`""`, ""},
{`"a"`, "a"},
{`"abc"`, "abc"},
@@ -146,23 +192,20 @@ var misquoted = []string{
}
func TestUnquote(t *testing.T) {
- for i := 0; i < len(unquotetests); i++ {
- tt := unquotetests[i]
+ for _, tt := range unquotetests {
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]
+ for _, tt := range quotetests {
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]
+ for _, s := range misquoted {
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/strings/reader.go b/libgo/go/strings/reader.go
index 914faa00359..eb515de0067 100644
--- a/libgo/go/strings/reader.go
+++ b/libgo/go/strings/reader.go
@@ -9,53 +9,83 @@ import (
"utf8"
)
-// A Reader satisfies calls to Read, ReadByte, and ReadRune by
-// reading from a string.
-type Reader string
+// A Reader implements the io.Reader, io.ByteScanner, and
+// io.RuneScanner interfaces by reading from a string.
+type Reader struct {
+ s string
+ i int // current reading index
+ prevRune int // index of previous rune; or < 0
+}
+
+// Len returns the number of bytes of the unread portion of the
+// string.
+func (r *Reader) Len() int {
+ return len(r.s) - r.i
+}
func (r *Reader) Read(b []byte) (n int, err os.Error) {
- s := *r
- if len(s) == 0 {
+ if r.i >= len(r.s) {
return 0, os.EOF
}
- for n < len(s) && n < len(b) {
- b[n] = s[n]
- n++
- }
- *r = s[n:]
+ n = copy(b, r.s[r.i:])
+ r.i += n
+ r.prevRune = -1
return
}
func (r *Reader) ReadByte() (b byte, err os.Error) {
- s := *r
- if len(s) == 0 {
+ if r.i >= len(r.s) {
return 0, os.EOF
}
- b = s[0]
- *r = s[1:]
+ b = r.s[r.i]
+ r.i++
+ r.prevRune = -1
return
}
+// UnreadByte moves the reading position back by one byte.
+// It is an error to call UnreadByte if nothing has been
+// read yet.
+func (r *Reader) UnreadByte() os.Error {
+ if r.i <= 0 {
+ return os.NewError("strings.Reader: at beginning of string")
+ }
+ r.i--
+ r.prevRune = -1
+ return 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 (r *Reader) ReadRune() (rune int, size int, err os.Error) {
- s := *r
- if len(s) == 0 {
+ if r.i >= len(r.s) {
return 0, 0, os.EOF
}
- c := s[0]
- if c < utf8.RuneSelf {
- *r = s[1:]
+ r.prevRune = r.i
+ if c := r.s[r.i]; c < utf8.RuneSelf {
+ r.i++
return int(c), 1, nil
}
- rune, size = utf8.DecodeRuneInString(string(s))
- *r = s[size:]
+ rune, size = utf8.DecodeRuneInString(r.s[r.i:])
+ r.i += size
return
}
+// UnreadRune causes the next call to ReadRune to return the same rune
+// as the previous call to ReadRune.
+// The last method called on r must have been ReadRune.
+func (r *Reader) UnreadRune() os.Error {
+ if r.prevRune < 0 {
+ return os.NewError("strings.Reader: previous operation was not ReadRune")
+ }
+ r.i = r.prevRune
+ r.prevRune = -1
+ return nil
+}
+
// 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) }
+func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go
index bfd057180d7..c547297e66c 100644
--- a/libgo/go/strings/strings.go
+++ b/libgo/go/strings/strings.go
@@ -198,26 +198,40 @@ func genSplit(s, sep string, sepSave, n int) []string {
return a[0 : na+1]
}
-// Split slices s into substrings separated by sep and returns a slice of
+// SplitN 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.
+// If sep is empty, SplitN 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) }
+func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
-// SplitAfter slices s into substrings after each instance of sep and
+// SplitAfterN 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.
+// If sep is empty, SplitAfterN 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 {
+func SplitAfterN(s, sep string, n int) []string {
return genSplit(s, sep, len(sep), n)
}
+// Split slices s into all 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.
+// It is equivalent to SplitN with a count of -1.
+func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) }
+
+// SplitAfter slices s into all substrings after each instance of sep and
+// returns a slice of those substrings.
+// If sep is empty, SplitAfter splits after each UTF-8 sequence.
+// It is equivalent to SplitAfterN with a count of -1.
+func SplitAfter(s, sep string) []string {
+ return genSplit(s, sep, len(sep), -1)
+}
+
// 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 {
@@ -349,7 +363,6 @@ func Repeat(s string, count int) string {
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) }
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
index c45b1485d8f..409d4da0e23 100644
--- a/libgo/go/strings/strings_test.go
+++ b/libgo/go/strings/strings_test.go
@@ -5,6 +5,7 @@
package strings_test
import (
+ "bytes"
"os"
"reflect"
"strconv"
@@ -169,7 +170,6 @@ func BenchmarkIndex(b *testing.B) {
}
}
-
type ExplodeTest struct {
s string
n int
@@ -185,7 +185,7 @@ var explodetests = []ExplodeTest{
func TestExplode(t *testing.T) {
for _, tt := range explodetests {
- a := Split(tt.s, "", tt.n)
+ a := SplitN(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
@@ -222,7 +222,7 @@ var splittests = []SplitTest{
func TestSplit(t *testing.T) {
for _, tt := range splittests {
- a := Split(tt.s, tt.sep, tt.n)
+ a := SplitN(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
@@ -234,6 +234,12 @@ func TestSplit(t *testing.T) {
if s != tt.s {
t.Errorf("Join(Split(%q, %q, %d), %q) = %q", tt.s, tt.sep, tt.n, tt.sep, s)
}
+ if tt.n < 0 {
+ b := Split(tt.s, tt.sep)
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("Split disagrees with SplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+ }
+ }
}
}
@@ -255,7 +261,7 @@ var splitaftertests = []SplitTest{
func TestSplitAfter(t *testing.T) {
for _, tt := range splitaftertests {
- a := SplitAfter(tt.s, tt.sep, tt.n)
+ a := SplitAfterN(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
@@ -264,6 +270,12 @@ func TestSplitAfter(t *testing.T) {
if s != tt.s {
t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s)
}
+ if tt.n < 0 {
+ b := SplitAfter(tt.s, tt.sep)
+ if !reflect.DeepEqual(a, b) {
+ t.Errorf("SplitAfter disagrees with SplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a)
+ }
+ }
}
}
@@ -312,7 +324,6 @@ func TestFieldsFunc(t *testing.T) {
}
}
-
// Test case for any function which accepts and returns a single string.
type StringTest struct {
in, out string
@@ -622,8 +633,8 @@ func equal(m string, s1, s2 string, t *testing.T) bool {
if s1 == s2 {
return true
}
- e1 := Split(s1, "", -1)
- e2 := Split(s2, "", -1)
+ e1 := Split(s1, "")
+ e2 := Split(s2, "")
for i, c1 := range e1 {
if i > len(e2) {
break
@@ -751,13 +762,56 @@ func TestRunes(t *testing.T) {
}
}
+func TestReadByte(t *testing.T) {
+ testStrings := []string{"", abcd, faces, commas}
+ for _, s := range testStrings {
+ reader := NewReader(s)
+ if e := reader.UnreadByte(); e == nil {
+ t.Errorf("Unreading %q at beginning: expected error", s)
+ }
+ var res bytes.Buffer
+ for {
+ b, e := reader.ReadByte()
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ t.Errorf("Reading %q: %s", s, e)
+ break
+ }
+ res.WriteByte(b)
+ // unread and read again
+ e = reader.UnreadByte()
+ if e != nil {
+ t.Errorf("Unreading %q: %s", s, e)
+ break
+ }
+ b1, e := reader.ReadByte()
+ if e != nil {
+ t.Errorf("Reading %q after unreading: %s", s, e)
+ break
+ }
+ if b1 != b {
+ t.Errorf("Reading %q after unreading: want byte %q, got %q", s, b, b1)
+ break
+ }
+ }
+ if res.String() != s {
+ t.Errorf("Reader(%q).ReadByte() produced %q", s, res.String())
+ }
+ }
+}
+
func TestReadRune(t *testing.T) {
testStrings := []string{"", abcd, faces, commas}
for _, s := range testStrings {
reader := NewReader(s)
+ if e := reader.UnreadRune(); e == nil {
+ t.Errorf("Unreading %q at beginning: expected error", s)
+ }
res := ""
for {
- r, _, e := reader.ReadRune()
+ r, z, e := reader.ReadRune()
if e == os.EOF {
break
}
@@ -766,6 +820,25 @@ func TestReadRune(t *testing.T) {
break
}
res += string(r)
+ // unread and read again
+ e = reader.UnreadRune()
+ if e != nil {
+ t.Errorf("Unreading %q: %s", s, e)
+ break
+ }
+ r1, z1, e := reader.ReadRune()
+ if e != nil {
+ t.Errorf("Reading %q after unreading: %s", s, e)
+ break
+ }
+ if r1 != r {
+ t.Errorf("Reading %q after unreading: want rune %q, got %q", s, r, r1)
+ break
+ }
+ if z1 != z {
+ t.Errorf("Reading %q after unreading: want size %d, got %d", s, z, z1)
+ break
+ }
}
if res != s {
t.Errorf("Reader(%q).ReadRune() produced %q", s, res)
diff --git a/libgo/go/sync/atomic/atomic.c b/libgo/go/sync/atomic/atomic.c
index e2d9b242fbd..6660a7d4a91 100644
--- a/libgo/go/sync/atomic/atomic.c
+++ b/libgo/go/sync/atomic/atomic.c
@@ -95,3 +95,31 @@ AddUintptr (uintptr_t *val, uintptr_t delta)
{
return __sync_add_and_fetch (val, delta);
}
+
+int32_t LoadInt32 (int32_t *addr)
+ asm ("libgo_sync.atomic.LoadInt32");
+
+int32_t
+LoadInt32 (int32_t *addr)
+{
+ int32_t v;
+
+ v = *addr;
+ while (! __sync_bool_compare_and_swap (addr, v, v))
+ v = *addr;
+ return v;
+}
+
+uint32_t LoadUint32 (uint32_t *addr)
+ asm ("libgo_sync.atomic.LoadUint32");
+
+uint32_t
+LoadUint32 (uint32_t *addr)
+{
+ uint32_t v;
+
+ v = *addr;
+ while (! __sync_bool_compare_and_swap (addr, v, v))
+ v = *addr;
+ return v;
+}
diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go
index 119ad0036fd..2229e58d0c7 100644
--- a/libgo/go/sync/atomic/atomic_test.go
+++ b/libgo/go/sync/atomic/atomic_test.go
@@ -308,6 +308,46 @@ func TestCompareAndSwapUintptr(t *testing.T) {
}
}
+func TestLoadInt32(t *testing.T) {
+ var x struct {
+ before int32
+ i int32
+ after int32
+ }
+ x.before = magic32
+ x.after = magic32
+ for delta := int32(1); delta+delta > delta; delta += delta {
+ k := LoadInt32(&x.i)
+ if k != x.i {
+ t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+ }
+ x.i += delta
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
+func TestLoadUint32(t *testing.T) {
+ var x struct {
+ before uint32
+ i uint32
+ after uint32
+ }
+ x.before = magic32
+ x.after = magic32
+ for delta := uint32(1); delta+delta > delta; delta += delta {
+ k := LoadUint32(&x.i)
+ if k != x.i {
+ t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
+ }
+ x.i += delta
+ }
+ if x.before != magic32 || x.after != magic32 {
+ t.Fatalf("wrong magic: %#x _ %#x != %#x _ %#x", x.before, x.after, magic32, magic32)
+ }
+}
+
// Tests of correct behavior, with contention.
// (Is the function atomic?)
//
@@ -537,3 +577,65 @@ func TestHammer64(t *testing.T) {
}
}
}
+
+func hammerLoadInt32(t *testing.T, uval *uint32) {
+ val := (*int32)(unsafe.Pointer(uval))
+ for {
+ v := LoadInt32(val)
+ vlo := v & ((1 << 16) - 1)
+ vhi := v >> 16
+ if vlo != vhi {
+ t.Fatalf("LoadInt32: %#x != %#x", vlo, vhi)
+ }
+ new := v + 1 + 1<<16
+ if vlo == 1e4 {
+ new = 0
+ }
+ if CompareAndSwapInt32(val, v, new) {
+ break
+ }
+ }
+}
+
+func hammerLoadUint32(t *testing.T, val *uint32) {
+ for {
+ v := LoadUint32(val)
+ vlo := v & ((1 << 16) - 1)
+ vhi := v >> 16
+ if vlo != vhi {
+ t.Fatalf("LoadUint32: %#x != %#x", vlo, vhi)
+ }
+ new := v + 1 + 1<<16
+ if vlo == 1e4 {
+ new = 0
+ }
+ if CompareAndSwapUint32(val, v, new) {
+ break
+ }
+ }
+}
+
+func TestHammerLoad(t *testing.T) {
+ tests := [...]func(*testing.T, *uint32){hammerLoadInt32, hammerLoadUint32}
+ n := 100000
+ if testing.Short() {
+ n = 10000
+ }
+ const procs = 8
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(procs))
+ for _, tt := range tests {
+ c := make(chan int)
+ var val uint32
+ for p := 0; p < procs; p++ {
+ go func() {
+ for i := 0; i < n; i++ {
+ tt(t, &val)
+ }
+ c <- 1
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+ }
+}
diff --git a/libgo/go/sync/atomic/doc.go b/libgo/go/sync/atomic/doc.go
index ec5a0d33af1..b35eb539c05 100644
--- a/libgo/go/sync/atomic/doc.go
+++ b/libgo/go/sync/atomic/doc.go
@@ -56,6 +56,12 @@ func AddUint64(val *uint64, delta uint64) (new uint64)
// AddUintptr atomically adds delta to *val and returns the new value.
func AddUintptr(val *uintptr, delta uintptr) (new uintptr)
+// LoadInt32 atomically loads *addr.
+func LoadInt32(addr *int32) (val int32)
+
+// LoadUint32 atomically loads *addr.
+func LoadUint32(addr *uint32) (val uint32)
+
// Helper for ARM. Linker will discard on other systems
func panic64() {
panic("sync/atomic: broken 64-bit atomic operations (buggy QEMU)")
diff --git a/libgo/go/sync/cond.go b/libgo/go/sync/cond.go
index ea48f2e7a98..75494b53536 100644
--- a/libgo/go/sync/cond.go
+++ b/libgo/go/sync/cond.go
@@ -14,10 +14,26 @@ import "runtime"
// which must be held when changing the condition and
// when calling the Wait method.
type Cond struct {
- L Locker // held while observing or changing the condition
- m Mutex // held to avoid internal races
- waiters int // number of goroutines blocked on Wait
- sema *uint32
+ L Locker // held while observing or changing the condition
+ m Mutex // held to avoid internal races
+
+ // We must be careful to make sure that when Signal
+ // releases a semaphore, the corresponding acquire is
+ // executed by a goroutine that was already waiting at
+ // the time of the call to Signal, not one that arrived later.
+ // To ensure this, we segment waiting goroutines into
+ // generations punctuated by calls to Signal. Each call to
+ // Signal begins another generation if there are no goroutines
+ // left in older generations for it to wake. Because of this
+ // optimization (only begin another generation if there
+ // are no older goroutines left), we only need to keep track
+ // of the two most recent generations, which we call old
+ // and new.
+ oldWaiters int // number of waiters in old generation...
+ oldSema *uint32 // ... waiting on this semaphore
+
+ newWaiters int // number of waiters in new generation...
+ newSema *uint32 // ... waiting on this semaphore
}
// NewCond returns a new Cond with Locker l.
@@ -42,11 +58,11 @@ func NewCond(l Locker) *Cond {
//
func (c *Cond) Wait() {
c.m.Lock()
- if c.sema == nil {
- c.sema = new(uint32)
+ if c.newSema == nil {
+ c.newSema = new(uint32)
}
- s := c.sema
- c.waiters++
+ s := c.newSema
+ c.newWaiters++
c.m.Unlock()
c.L.Unlock()
runtime.Semacquire(s)
@@ -59,9 +75,16 @@ func (c *Cond) Wait() {
// during the call.
func (c *Cond) Signal() {
c.m.Lock()
- if c.waiters > 0 {
- c.waiters--
- runtime.Semrelease(c.sema)
+ if c.oldWaiters == 0 && c.newWaiters > 0 {
+ // Retire old generation; rename new to old.
+ c.oldWaiters = c.newWaiters
+ c.oldSema = c.newSema
+ c.newWaiters = 0
+ c.newSema = nil
+ }
+ if c.oldWaiters > 0 {
+ c.oldWaiters--
+ runtime.Semrelease(c.oldSema)
}
c.m.Unlock()
}
@@ -72,19 +95,19 @@ func (c *Cond) Signal() {
// during the call.
func (c *Cond) Broadcast() {
c.m.Lock()
- if c.waiters > 0 {
- s := c.sema
- n := c.waiters
- for i := 0; i < n; i++ {
- runtime.Semrelease(s)
+ // Wake both generations.
+ if c.oldWaiters > 0 {
+ for i := 0; i < c.oldWaiters; i++ {
+ runtime.Semrelease(c.oldSema)
+ }
+ c.oldWaiters = 0
+ }
+ if c.newWaiters > 0 {
+ for i := 0; i < c.newWaiters; i++ {
+ runtime.Semrelease(c.newSema)
}
- // We just issued n wakeups via the semaphore s.
- // To ensure that they wake up the existing waiters
- // and not waiters that arrive after Broadcast returns,
- // clear c.sema. The next operation will allocate
- // a new one.
- c.sema = nil
- c.waiters = 0
+ c.newWaiters = 0
+ c.newSema = nil
}
c.m.Unlock()
}
diff --git a/libgo/go/sync/cond_test.go b/libgo/go/sync/cond_test.go
index 846f98bf39d..cefacb184e1 100644
--- a/libgo/go/sync/cond_test.go
+++ b/libgo/go/sync/cond_test.go
@@ -46,6 +46,33 @@ func TestCondSignal(t *testing.T) {
c.Signal()
}
+func TestCondSignalGenerations(t *testing.T) {
+ var m Mutex
+ c := NewCond(&m)
+ n := 100
+ running := make(chan bool, n)
+ awake := make(chan int, n)
+ for i := 0; i < n; i++ {
+ go func(i int) {
+ m.Lock()
+ running <- true
+ c.Wait()
+ awake <- i
+ m.Unlock()
+ }(i)
+ if i > 0 {
+ a := <-awake
+ if a != i-1 {
+ t.Fatalf("wrong goroutine woke up: want %d, got %d", i-1, a)
+ }
+ }
+ <-running
+ m.Lock()
+ c.Signal()
+ m.Unlock()
+ }
+}
+
func TestCondBroadcast(t *testing.T) {
var m Mutex
c := NewCond(&m)
diff --git a/libgo/go/sync/mutex.go b/libgo/go/sync/mutex.go
index 13f03cad394..2d46c89948f 100644
--- a/libgo/go/sync/mutex.go
+++ b/libgo/go/sync/mutex.go
@@ -17,8 +17,8 @@ import (
// Mutexes can be created as part of other structures;
// the zero value for a Mutex is an unlocked mutex.
type Mutex struct {
- key int32
- sema uint32
+ state int32
+ sema uint32
}
// A Locker represents an object that can be locked and unlocked.
@@ -27,15 +27,41 @@ type Locker interface {
Unlock()
}
+const (
+ mutexLocked = 1 << iota // mutex is locked
+ mutexWoken
+ mutexWaiterShift = iota
+)
+
// Lock locks m.
// If the lock is already in use, the calling goroutine
// blocks until the mutex is available.
func (m *Mutex) Lock() {
- if atomic.AddInt32(&m.key, 1) == 1 {
- // changed from 0 to 1; we hold lock
+ // Fast path: grab unlocked mutex.
+ if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
return
}
- runtime.Semacquire(&m.sema)
+
+ awoke := false
+ for {
+ old := m.state
+ new := old | mutexLocked
+ if old&mutexLocked != 0 {
+ new = old + 1<<mutexWaiterShift
+ }
+ if awoke {
+ // The goroutine has been woken from sleep,
+ // so we need to reset the flag in either case.
+ new &^= mutexWoken
+ }
+ if atomic.CompareAndSwapInt32(&m.state, old, new) {
+ if old&mutexLocked == 0 {
+ break
+ }
+ runtime.Semacquire(&m.sema)
+ awoke = true
+ }
+ }
}
// Unlock unlocks m.
@@ -45,14 +71,25 @@ func (m *Mutex) Lock() {
// It is allowed for one goroutine to lock a Mutex and then
// arrange for another goroutine to unlock it.
func (m *Mutex) Unlock() {
- switch v := atomic.AddInt32(&m.key, -1); {
- case v == 0:
- // changed from 1 to 0; no contention
- return
- case v == -1:
- // changed from 0 to -1: wasn't locked
- // (or there are 4 billion goroutines waiting)
+ // Fast path: drop lock bit.
+ new := atomic.AddInt32(&m.state, -mutexLocked)
+ if (new+mutexLocked)&mutexLocked == 0 {
panic("sync: unlock of unlocked mutex")
}
- runtime.Semrelease(&m.sema)
+
+ old := new
+ for {
+ // If there are no waiters or a goroutine has already
+ // been woken or grabbed the lock, no need to wake anyone.
+ if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
+ return
+ }
+ // Grab the right to wake someone.
+ new = (old - 1<<mutexWaiterShift) | mutexWoken
+ if atomic.CompareAndSwapInt32(&m.state, old, new) {
+ runtime.Semrelease(&m.sema)
+ return
+ }
+ old = m.state
+ }
}
diff --git a/libgo/go/sync/mutex_test.go b/libgo/go/sync/mutex_test.go
index f5c20ca49b4..47758844f27 100644
--- a/libgo/go/sync/mutex_test.go
+++ b/libgo/go/sync/mutex_test.go
@@ -9,6 +9,7 @@ package sync_test
import (
"runtime"
. "sync"
+ "sync/atomic"
"testing"
)
@@ -43,7 +44,7 @@ func BenchmarkContendedSemaphore(b *testing.B) {
s := new(uint32)
*s = 1
c := make(chan bool)
- runtime.GOMAXPROCS(2)
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
b.StartTimer()
go HammerSemaphore(s, b.N/2, c)
@@ -52,7 +53,6 @@ func BenchmarkContendedSemaphore(b *testing.B) {
<-c
}
-
func HammerMutex(m *Mutex, loops int, cdone chan bool) {
for i := 0; i < loops; i++ {
m.Lock()
@@ -72,24 +72,6 @@ func TestMutex(t *testing.T) {
}
}
-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
-}
-
func TestMutexPanic(t *testing.T) {
defer func() {
if recover() == nil {
@@ -102,3 +84,83 @@ func TestMutexPanic(t *testing.T) {
mu.Unlock()
mu.Unlock()
}
+
+func BenchmarkMutexUncontended(b *testing.B) {
+ type PaddedMutex struct {
+ Mutex
+ pad [128]uint8
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ var mu PaddedMutex
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ mu.Lock()
+ mu.Unlock()
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkMutex(b *testing.B, slack, work bool) {
+ const (
+ CallsPerSched = 1000
+ LocalWork = 100
+ GoroutineSlack = 10
+ )
+ procs := runtime.GOMAXPROCS(-1)
+ if slack {
+ procs *= GoroutineSlack
+ }
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ var mu Mutex
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ mu.Lock()
+ mu.Unlock()
+ if work {
+ for i := 0; i < LocalWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkMutex(b *testing.B) {
+ benchmarkMutex(b, false, false)
+}
+
+func BenchmarkMutexSlack(b *testing.B) {
+ benchmarkMutex(b, true, false)
+}
+
+func BenchmarkMutexWork(b *testing.B) {
+ benchmarkMutex(b, false, true)
+}
+
+func BenchmarkMutexWorkSlack(b *testing.B) {
+ benchmarkMutex(b, true, true)
+}
diff --git a/libgo/go/sync/once.go b/libgo/go/sync/once.go
index b6f5f5a8726..04b714a3e74 100644
--- a/libgo/go/sync/once.go
+++ b/libgo/go/sync/once.go
@@ -4,10 +4,14 @@
package sync
+import (
+ "sync/atomic"
+)
+
// Once is an object that will perform exactly one action.
type Once struct {
m Mutex
- done bool
+ done uint32
}
// Do calls the function f if and only if the method is being called for the
@@ -26,10 +30,14 @@ type Once struct {
// Do to be called, it will deadlock.
//
func (o *Once) Do(f func()) {
+ if atomic.LoadUint32(&o.done) == 1 {
+ return
+ }
+ // Slow-path.
o.m.Lock()
defer o.m.Unlock()
- if !o.done {
- o.done = true
+ if o.done == 0 {
f()
+ atomic.CompareAndSwapUint32(&o.done, 0, 1)
}
}
diff --git a/libgo/go/sync/once_test.go b/libgo/go/sync/once_test.go
index 155954a49b5..157a3667a64 100644
--- a/libgo/go/sync/once_test.go
+++ b/libgo/go/sync/once_test.go
@@ -6,6 +6,8 @@ package sync_test
import (
. "sync"
+ "sync/atomic"
+ "runtime"
"testing"
)
@@ -35,3 +37,26 @@ func TestOnce(t *testing.T) {
t.Errorf("once failed: %d is not 1", *o)
}
}
+
+func BenchmarkOnce(b *testing.B) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ var once Once
+ f := func() {}
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ once.Do(f)
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
diff --git a/libgo/go/sync/rwmutex.go b/libgo/go/sync/rwmutex.go
index 9248b4b0370..cb1a47720b2 100644
--- a/libgo/go/sync/rwmutex.go
+++ b/libgo/go/sync/rwmutex.go
@@ -4,7 +4,10 @@
package sync
-import "sync/atomic"
+import (
+ "runtime"
+ "sync/atomic"
+)
// An RWMutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers
@@ -12,35 +15,22 @@ import "sync/atomic"
// 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 int32 // number of pending readers
+ w Mutex // held if there are pending writers
+ writerSem uint32 // semaphore for writers to wait for completing readers
+ readerSem uint32 // semaphore for readers to wait for completing writers
+ readerCount int32 // number of pending readers
+ readerWait int32 // number of departing readers
}
+const rwmutexMaxReaders = 1 << 30
+
// 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 atomic.AddInt32(&rw.readerCount, 1) == 1 {
- // The first reader locks rw.w, so writers will be blocked
- // while the readers have the RLock.
- rw.w.Lock()
+ if atomic.AddInt32(&rw.readerCount, 1) < 0 {
+ // A writer is pending, wait for it.
+ runtime.Semacquire(&rw.readerSem)
}
- rw.r.Unlock()
}
// RUnlock undoes a single RLock call;
@@ -48,9 +38,12 @@ func (rw *RWMutex) RLock() {
// It is a run-time error if rw is not locked for reading
// on entry to RUnlock.
func (rw *RWMutex) RUnlock() {
- if atomic.AddInt32(&rw.readerCount, -1) == 0 {
- // last reader finished, enable writers
- rw.w.Unlock()
+ if atomic.AddInt32(&rw.readerCount, -1) < 0 {
+ // A writer is pending.
+ if atomic.AddInt32(&rw.readerWait, -1) == 0 {
+ // The last reader unblocks the writer.
+ runtime.Semrelease(&rw.writerSem)
+ }
}
}
@@ -61,9 +54,14 @@ func (rw *RWMutex) RUnlock() {
// a blocked Lock call excludes new readers from acquiring
// the lock.
func (rw *RWMutex) Lock() {
- rw.r.Lock()
+ // First, resolve competition with other writers.
rw.w.Lock()
- rw.r.Unlock()
+ // Announce to readers there is a pending writer.
+ r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
+ // Wait for active readers.
+ if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
+ runtime.Semacquire(&rw.writerSem)
+ }
}
// Unlock unlocks rw for writing. It is a run-time error if rw is
@@ -72,7 +70,16 @@ func (rw *RWMutex) Lock() {
// As with Mutexes, a locked RWMutex is not associated with a particular
// goroutine. One goroutine may RLock (Lock) an RWMutex and then
// arrange for another goroutine to RUnlock (Unlock) it.
-func (rw *RWMutex) Unlock() { rw.w.Unlock() }
+func (rw *RWMutex) Unlock() {
+ // Announce to readers there is no active writer.
+ r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
+ // Unblock blocked readers, if any.
+ for i := 0; i < int(r); i++ {
+ runtime.Semrelease(&rw.readerSem)
+ }
+ // Allow other writers to proceed.
+ rw.w.Unlock()
+}
// RLocker returns a Locker interface that implements
// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
diff --git a/libgo/go/sync/rwmutex_test.go b/libgo/go/sync/rwmutex_test.go
index 9fb89f8e8a3..dc8ce9653ce 100644
--- a/libgo/go/sync/rwmutex_test.go
+++ b/libgo/go/sync/rwmutex_test.go
@@ -45,6 +45,7 @@ func doTestParallelReaders(numReaders, gomaxprocs int) {
}
func TestParallelReaders(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
doTestParallelReaders(1, 4)
doTestParallelReaders(3, 4)
doTestParallelReaders(4, 2)
@@ -102,6 +103,7 @@ func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) {
}
func TestRWMutex(t *testing.T) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1))
n := 1000
if testing.Short() {
n = 5
@@ -152,3 +154,84 @@ func TestRLocker(t *testing.T) {
wl.Unlock()
}
}
+
+func BenchmarkRWMutexUncontended(b *testing.B) {
+ type PaddedRWMutex struct {
+ RWMutex
+ pad [32]uint32
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ var rwm PaddedRWMutex
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ rwm.RLock()
+ rwm.RLock()
+ rwm.RUnlock()
+ rwm.RUnlock()
+ rwm.Lock()
+ rwm.Unlock()
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkRWMutex(b *testing.B, localWork, writeRatio int) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ var rwm RWMutex
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ foo++
+ if foo%writeRatio == 0 {
+ rwm.Lock()
+ rwm.Unlock()
+ } else {
+ rwm.RLock()
+ for i := 0; i != localWork; i += 1 {
+ foo *= 2
+ foo /= 2
+ }
+ rwm.RUnlock()
+ }
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkRWMutexWrite100(b *testing.B) {
+ benchmarkRWMutex(b, 0, 100)
+}
+
+func BenchmarkRWMutexWrite10(b *testing.B) {
+ benchmarkRWMutex(b, 0, 10)
+}
+
+func BenchmarkRWMutexWorkWrite100(b *testing.B) {
+ benchmarkRWMutex(b, 100, 100)
+}
+
+func BenchmarkRWMutexWorkWrite10(b *testing.B) {
+ benchmarkRWMutex(b, 100, 10)
+}
diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go
index 05478c63066..a4c9b7e43cd 100644
--- a/libgo/go/sync/waitgroup.go
+++ b/libgo/go/sync/waitgroup.go
@@ -4,7 +4,10 @@
package sync
-import "runtime"
+import (
+ "runtime"
+ "sync/atomic"
+)
// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
@@ -28,8 +31,8 @@ import "runtime"
//
type WaitGroup struct {
m Mutex
- counter int
- waiters int
+ counter int32
+ waiters int32
sema *uint32
}
@@ -48,19 +51,19 @@ type WaitGroup struct {
// Add adds delta, which may be negative, to the WaitGroup counter.
// If the counter becomes zero, all goroutines blocked on Wait() are released.
func (wg *WaitGroup) Add(delta int) {
- wg.m.Lock()
- if delta < -wg.counter {
- wg.m.Unlock()
+ v := atomic.AddInt32(&wg.counter, int32(delta))
+ if v < 0 {
panic("sync: negative WaitGroup count")
}
- wg.counter += delta
- if wg.counter == 0 && wg.waiters > 0 {
- for i := 0; i < wg.waiters; i++ {
- runtime.Semrelease(wg.sema)
- }
- wg.waiters = 0
- wg.sema = nil
+ if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
+ return
}
+ wg.m.Lock()
+ for i := int32(0); i < wg.waiters; i++ {
+ runtime.Semrelease(wg.sema)
+ }
+ wg.waiters = 0
+ wg.sema = nil
wg.m.Unlock()
}
@@ -71,12 +74,20 @@ func (wg *WaitGroup) Done() {
// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
+ if atomic.LoadInt32(&wg.counter) == 0 {
+ return
+ }
wg.m.Lock()
- if wg.counter == 0 {
+ atomic.AddInt32(&wg.waiters, 1)
+ // This code is racing with the unlocked path in Add above.
+ // The code above modifies counter and then reads waiters.
+ // We must modify waiters and then read counter (the opposite order)
+ // to avoid missing an Add.
+ if atomic.LoadInt32(&wg.counter) == 0 {
+ atomic.AddInt32(&wg.waiters, -1)
wg.m.Unlock()
return
}
- wg.waiters++
if wg.sema == nil {
wg.sema = new(uint32)
}
diff --git a/libgo/go/sync/waitgroup_test.go b/libgo/go/sync/waitgroup_test.go
index fe35732e7a6..34430fc2158 100644
--- a/libgo/go/sync/waitgroup_test.go
+++ b/libgo/go/sync/waitgroup_test.go
@@ -5,7 +5,9 @@
package sync_test
import (
+ "runtime"
. "sync"
+ "sync/atomic"
"testing"
)
@@ -58,3 +60,106 @@ func TestWaitGroupMisuse(t *testing.T) {
wg.Done()
t.Fatal("Should panic")
}
+
+func BenchmarkWaitGroupUncontended(b *testing.B) {
+ type PaddedWaitGroup struct {
+ WaitGroup
+ pad [128]uint8
+ }
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ for p := 0; p < procs; p++ {
+ go func() {
+ var wg PaddedWaitGroup
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ wg.Add(1)
+ wg.Done()
+ wg.Wait()
+ }
+ }
+ c <- true
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ var wg WaitGroup
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ wg.Add(1)
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ wg.Done()
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkWaitGroupAddDone(b *testing.B) {
+ benchmarkWaitGroupAddDone(b, 0)
+}
+
+func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
+ benchmarkWaitGroupAddDone(b, 100)
+}
+
+func benchmarkWaitGroupWait(b *testing.B, localWork int) {
+ const CallsPerSched = 1000
+ procs := runtime.GOMAXPROCS(-1)
+ N := int32(b.N / CallsPerSched)
+ c := make(chan bool, procs)
+ var wg WaitGroup
+ wg.Add(procs)
+ for p := 0; p < procs; p++ {
+ go wg.Done()
+ }
+ for p := 0; p < procs; p++ {
+ go func() {
+ foo := 0
+ for atomic.AddInt32(&N, -1) >= 0 {
+ runtime.Gosched()
+ for g := 0; g < CallsPerSched; g++ {
+ wg.Wait()
+ for i := 0; i < localWork; i++ {
+ foo *= 2
+ foo /= 2
+ }
+ }
+ }
+ c <- foo == 42
+ }()
+ }
+ for p := 0; p < procs; p++ {
+ <-c
+ }
+}
+
+func BenchmarkWaitGroupWait(b *testing.B) {
+ benchmarkWaitGroupWait(b, 0)
+}
+
+func BenchmarkWaitGroupWaitWork(b *testing.B) {
+ benchmarkWaitGroupWait(b, 100)
+}
diff --git a/libgo/go/syslog/syslog_unix.go b/libgo/go/syslog/syslog_unix.go
index fa15e882d07..b1516715bca 100644
--- a/libgo/go/syslog/syslog_unix.go
+++ b/libgo/go/syslog/syslog_unix.go
@@ -27,5 +27,5 @@ func unixSyslog() (conn serverConn, err os.Error) {
}
}
}
- return nil, os.ErrorString("Unix syslog delivery error")
+ return nil, os.NewError("Unix syslog delivery error")
}
diff --git a/libgo/go/tabwriter/tabwriter.go b/libgo/go/tabwriter/tabwriter.go
index d91a07db242..2f35d961eb2 100644
--- a/libgo/go/tabwriter/tabwriter.go
+++ b/libgo/go/tabwriter/tabwriter.go
@@ -17,7 +17,6 @@ import (
"utf8"
)
-
// ----------------------------------------------------------------------------
// Filter implementation
@@ -32,7 +31,6 @@ type cell struct {
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.
//
@@ -95,10 +93,8 @@ type Writer struct {
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()
@@ -110,7 +106,6 @@ func (b *Writer) reset() {
b.addLine()
}
-
// Internal representation (current state):
//
// - all text written is appended to buf; tabs and line breaks are stripped away
@@ -134,7 +129,6 @@ func (b *Writer) reset() {
// | | |
// buf start of incomplete cell pos
-
// Formatting can be controlled with these flags.
const (
// Ignore html tags and treat entities (starting with '&'
@@ -158,11 +152,10 @@ const (
TabIndent
// Print a vertical bar ('|') between columns (after formatting).
- // Discarded colums appear as zero-width columns ("||").
+ // Discarded columns 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:
//
@@ -205,7 +198,6 @@ func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar
return b
}
-
// debugging support (keep code around)
func (b *Writer) dump() {
pos := 0
@@ -220,14 +212,12 @@ func (b *Writer) dump() {
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 {
@@ -238,7 +228,6 @@ func (b *Writer) write0(buf []byte) {
}
}
-
func (b *Writer) writeN(src []byte, n int) {
for n > len(src) {
b.write0(src)
@@ -247,13 +236,11 @@ func (b *Writer) writeN(src []byte, n int) {
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
@@ -274,7 +261,6 @@ func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
b.writeN(b.padbytes[0:], cellw-textw)
}
-
var vbar = []byte{'|'}
func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
@@ -328,7 +314,6 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
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
@@ -392,21 +377,18 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
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
@@ -416,7 +398,6 @@ func (b *Writer) updateWidth() {
//
const Escape = '\xff'
-
// Start escaped mode.
func (b *Writer) startEscape(ch byte) {
switch ch {
@@ -429,7 +410,6 @@ func (b *Writer) startEscape(ch byte) {
}
}
-
// 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
@@ -450,7 +430,6 @@ func (b *Writer) endEscape() {
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.
//
@@ -462,14 +441,12 @@ func (b *Writer) terminateCell(htab bool) int {
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
@@ -494,7 +471,6 @@ func (b *Writer) Flush() (err os.Error) {
return
}
-
var hbar = []byte("---\n")
// Write writes buf to the writer b.
@@ -577,7 +553,6 @@ func (b *Writer) Write(buf []byte) (n int, err os.Error) {
return
}
-
// NewWriter allocates and initializes a new tabwriter.Writer.
// The parameters are the same as for the the Init function.
//
diff --git a/libgo/go/tabwriter/tabwriter_test.go b/libgo/go/tabwriter/tabwriter_test.go
index 043d9154e10..6ef7e808eff 100644
--- a/libgo/go/tabwriter/tabwriter_test.go
+++ b/libgo/go/tabwriter/tabwriter_test.go
@@ -10,18 +10,14 @@ import (
"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)
@@ -36,10 +32,8 @@ func (b *buffer) Write(buf []byte) (written int, err os.Error) {
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 {
@@ -50,7 +44,6 @@ func write(t *testing.T, testname string, w *Writer, src string) {
}
}
-
func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
err := w.Flush()
if err != nil {
@@ -63,7 +56,6 @@ func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected s
}
}
-
func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padchar byte, flags uint, src, expected string) {
var b buffer
b.init(1000)
@@ -98,7 +90,6 @@ func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padch
verify(t, title, &w, &b, src, expected)
}
-
var tests = []struct {
testname string
minwidth, tabwidth, padding int
@@ -617,7 +608,6 @@ var tests = []struct {
},
}
-
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/doc.go b/libgo/go/template/doc.go
new file mode 100644
index 00000000000..a52f32d91b9
--- /dev/null
+++ b/libgo/go/template/doc.go
@@ -0,0 +1,313 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package template implements 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.
+Execution of the template walks the structure and sets the cursor, represented
+by a period '.' and called "dot", to the value at the current location in the
+structure as execution proceeds.
+
+The input text for a template is UTF-8-encoded text in any format.
+"Actions"--data evaluations or control structures--are delimited by
+"{{" and "}}"; all text outside actions is copied to the output unchanged.
+Actions may not span newlines, although comments can.
+
+Once constructed, templates and template sets can be executed safely in
+parallel.
+
+Actions
+
+Here is the list of actions. "Arguments" and "pipelines" are evaluations of
+data, defined in detail below.
+
+*/
+// {{/* a comment */}}
+// A comment; discarded. May contain newlines.
+// Comments do not nest.
+/*
+
+ {{pipeline}}
+ The default textual representation of the value of the pipeline
+ is copied to the output.
+
+ {{if pipeline}} T1 {{end}}
+ If the value of the pipeline is empty, no output is generated;
+ otherwise, T1 is executed. The empty values are false, 0, any
+ nil pointer or interface value, and any array, slice, map, or
+ string of length zero.
+ Dot is unaffected.
+
+ {{if pipeline}} T1 {{else}} T0 {{end}}
+ If the value of the pipeline is empty, T0 is executed;
+ otherwise, T1 is executed. Dot is unaffected.
+
+ {{range pipeline}} T1 {{end}}
+ The value of the pipeline must be an array, slice, or map. If
+ the value of the pipeline has length zero, nothing is output;
+ otherwise, dot is set to the successive elements of the array,
+ slice, or map and T1 is executed.
+
+ {{range pipeline}} T1 {{else}} T0 {{end}}
+ The value of the pipeline must be an array, slice, or map. If
+ the value of the pipeline has length zero, dot is unaffected and
+ T0 is executed; otherwise, dot is set to the successive elements
+ of the array, slice, or map and T1 is executed.
+
+ {{template "name"}}
+ The template with the specified name is executed with nil data.
+
+ {{template "name" pipeline}}
+ The template with the specified name is executed with dot set
+ to the value of the pipeline.
+
+ {{with pipeline}} T1 {{end}}
+ If the value of the pipeline is empty, no output is generated;
+ otherwise, dot is set to the value of the pipeline and T1 is
+ executed.
+
+ {{with pipeline}} T1 {{else}} T0 {{end}}
+ If the value of the pipeline is empty, dot is unaffected and T0
+ is executed; otherwise, dot is set to the value of the pipeline
+ and T1 is executed.
+
+Arguments
+
+An argument is a simple value, denoted by one of the following.
+
+ - A boolean, string, character, integer, floating-point, imaginary
+ or complex constant in Go syntax. These behave like Go's untyped
+ constants, although raw strings may not span newlines.
+ - The character '.' (period):
+ .
+ The result is the value of dot.
+ - A variable name, which is a (possibly empty) alphanumeric string
+ preceded by a dollar sign, such as
+ $piOver2
+ or
+ $
+ The result is the value of the variable.
+ Variables are described below.
+ - The name of a field of the data, which must be a struct, preceded
+ by a period, such as
+ .Field
+ The result is the value of the field. Field invocations may be
+ chained:
+ .Field1.Field2
+ Fields can also be evaluated on variables, including chaining:
+ $x.Field1.Field2
+ - The name of a key of the data, which must be a map, preceded
+ by a period, such as
+ .Key
+ The result is the map element value indexed by the key.
+ Key invocations may be chained and combined with fields to any
+ depth:
+ .Field1.Key1.Field2.Key2
+ Although the key must be an alphanumeric identifier, unlike with
+ field names they do not need to start with an upper case letter.
+ Keys can also be evaluated on variables, including chaining:
+ $x.key1.key2
+ - The name of a niladic method of the data, preceded by a period,
+ such as
+ .Method
+ The result is the value of invoking the method with dot as the
+ receiver, dot.Method(). Such a method must have one return value (of
+ any type) or two return values, the second of which is an os.Error.
+ If it has two and the returned error is non-nil, execution terminates
+ and an error is returned to the caller as the value of Execute.
+ Method invocations may be chained and combined with fields and keys
+ to any depth:
+ .Field1.Key1.Method1.Field2.Key2.Method2
+ Methods can also be evaluated on variables, including chaining:
+ $x.Method1.Field
+ - The name of a niladic function, such as
+ fun
+ The result is the value of invoking the function, fun(). The return
+ types and values behave as in methods. Functions and function
+ names are described below.
+
+Arguments may evaluate to any type; if they are pointers the implementation
+automatically indirects to the base type when required.
+
+A pipeline is a possibly chained sequence of "commands". A command is a simple
+value (argument) or a function or method call, possibly with multiple arguments:
+
+ Argument
+ The result is the value of evaluating the argument.
+ .Method [Argument...]
+ The method can be alone or the last element of a chain but,
+ unlike methods in the middle of a chain, it can take arguments.
+ The result is the value of calling the method with the
+ arguments:
+ dot.Method(Argument1, etc.)
+ functionName [Argument...]
+ The result is the value of calling the function associated
+ with the name:
+ function(Argument1, etc.)
+ Functions and function names are described below.
+
+Pipelines
+
+A pipeline may be "chained" by separating a sequence of commands with pipeline
+characters '|'. In a chained pipeline, the result of the each command is
+passed as the last argument of the following command. The output of the final
+command in the pipeline is the value of the pipeline.
+
+The output of a command will be either one value or two values, the second of
+which has type os.Error. If that second value is present and evaluates to
+non-nil, execution terminates and the error is returned to the caller of
+Execute.
+
+Variables
+
+A pipeline inside an action may initialize a variable to capture the result.
+The initialization has syntax
+
+ $variable := pipeline
+
+where $variable is the name of the variable. An action that declares a
+variable produces no output.
+
+If a "range" action initializes a variable, the variable is set to the
+successive elements of the iteration. Also, a "range" may declare two
+variables, separated by a comma:
+
+ $index, $element := pipeline
+
+in which case $index and $element are set to the successive values of the
+array/slice index or map key and element, respectively. Note that if there is
+only one variable, it is assigned the element; this is opposite to the
+convention in Go range clauses.
+
+A variable's scope extends to the "end" action of the control structure ("if",
+"with", or "range") in which it is declared, or to the end of the template if
+there is no such control structure. A template invocation does not inherit
+variables from the point of its invocation.
+
+When execution begins, $ is set to the data argument passed to Execute, that is,
+to the starting value of dot.
+
+Examples
+
+Here are some example one-line templates demonstrating pipelines and variables.
+All produce the quoted word "output":
+
+ {{"\"output\""}}
+ A string constant.
+ {{`"output"`}}
+ A raw string constant.
+ {{printf "%q" "output"}}
+ A function call.
+ {{"output" | printf "%q"}}
+ A function call whose final argument comes from the previous
+ command.
+ {{"put" | printf "%s%s" "out" | printf "%q"}}
+ A more elaborate call.
+ {{"output" | printf "%s" | printf "%q"}}
+ A longer chain.
+ {{with "output"}}{{printf "%q" .}}{{end}}
+ A with action using dot.
+ {{with $x := "output" | printf "%q"}}{{$x}}{{end}}
+ A with action that creates and uses a variable.
+ {{with $x := "output"}}{{printf "%q" $x}}{{end}}
+ A with action that uses the variable in another action.
+ {{with $x := "output"}}{{$x | printf "%q"}}{{end}}
+ The same, but pipelined.
+
+Functions
+
+During execution functions are found in three function maps: first in the
+template, then in the "template set" (described below), and finally in the
+global function map. By default, no functions are defined in the template or
+the set but the Funcs methods can be used to add them.
+
+Predefined global functions are named as follows.
+
+ and
+ Returns the boolean AND of its arguments by returning the
+ first empty argument or the last argument, that is,
+ "and x y" behaves as "if x then y else x". All the
+ arguments are evaluated.
+ html
+ Returns the escaped HTML equivalent of the textual
+ representation of its arguments.
+ index
+ Returns the result of indexing its first argument by the
+ following arguments. Thus "index x 1 2 3" is, in Go syntax,
+ x[1][2][3]. Each indexed item must be a map, slice, or array.
+ js
+ Returns the escaped JavaScript equivalent of the textual
+ representation of its arguments.
+ len
+ Returns the integer length of its argument.
+ not
+ Returns the boolean negation of its single argument.
+ or
+ Returns the boolean OR of its arguments by returning the
+ first non-empty argument or the last argument, that is,
+ "or x y" behaves as "if x then x else y". All the
+ arguments are evaluated.
+ print
+ An alias for fmt.Sprint
+ printf
+ An alias for fmt.Sprintf
+ println
+ An alias for fmt.Sprintln
+ urlquery
+ Returns the escaped value of the textual representation of
+ its arguments in a form suitable for embedding in a URL query.
+
+The boolean functions take any zero value to be false and a non-zero value to
+be true.
+
+Template sets
+
+Each template is named by a string specified when it is created. A template may
+use a template invocation to instantiate another template directly or by its
+name; see the explanation of the template action above. The name is looked up
+in the template set associated with the template.
+
+If no template invocation actions occur in the template, the issue of template
+sets can be ignored. If it does contain invocations, though, the template
+containing the invocations must be part of a template set in which to look up
+the names.
+
+There are two ways to construct template sets.
+
+The first is to use a Set's Parse method to create a set of named templates from
+a single input defining multiple templates. The syntax of the definitions is to
+surround each template declaration with a define and end action.
+
+The define action names the template being created by providing a string
+constant. Here is a simple example of input to Set.Parse:
+
+ `{{define "T1"}} definition of template T1 {{end}}
+ {{define "T2"}} definition of template T2 {{end}}
+ {{define "T3"}} {{template "T1"}} {{template "T2"}} {{end}}`
+
+This defines two templates, T1 and T2, and a third T3 that invokes the other two
+when it is executed.
+
+The second way to build a template set is to use Set's Add method to add a
+parsed template to a set. A template may be bound to at most one set. If it's
+necessary to have a template in multiple sets, the template definition must be
+parsed multiple times to create distinct *Template values.
+
+Set.Parse may be called multiple times on different inputs to construct the set.
+Two sets may therefore be constructed with a common base set of templates plus,
+through a second Parse call each, specializations for some elements.
+
+A template may be executed directly or through Set.Execute, which executes a
+named template from the set. To invoke our example above, we might write,
+
+ err := set.Execute(os.Stdout, "T3", "no data needed")
+ if err != nil {
+ log.Fatalf("execution failed: %s", err)
+ }
+*/
+package template
diff --git a/libgo/go/template/exec.go b/libgo/go/template/exec.go
new file mode 100644
index 00000000000..f1590b3bb63
--- /dev/null
+++ b/libgo/go/template/exec.go
@@ -0,0 +1,674 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "runtime"
+ "strings"
+ "template/parse"
+)
+
+// state represents the state of an execution. It's not part of the
+// template so that multiple executions of the same template
+// can execute in parallel.
+type state struct {
+ tmpl *Template
+ wr io.Writer
+ line int // line number for errors
+ vars []variable // push-down stack of variable values.
+}
+
+// variable holds the dynamic value of a variable such as $, $x etc.
+type variable struct {
+ name string
+ value reflect.Value
+}
+
+// push pushes a new variable on the stack.
+func (s *state) push(name string, value reflect.Value) {
+ s.vars = append(s.vars, variable{name, value})
+}
+
+// mark returns the length of the variable stack.
+func (s *state) mark() int {
+ return len(s.vars)
+}
+
+// pop pops the variable stack up to the mark.
+func (s *state) pop(mark int) {
+ s.vars = s.vars[0:mark]
+}
+
+// setVar overwrites the top-nth variable on the stack. Used by range iterations.
+func (s *state) setVar(n int, value reflect.Value) {
+ s.vars[len(s.vars)-n].value = value
+}
+
+// varValue returns the value of the named variable.
+func (s *state) varValue(name string) reflect.Value {
+ for i := s.mark() - 1; i >= 0; i-- {
+ if s.vars[i].name == name {
+ return s.vars[i].value
+ }
+ }
+ s.errorf("undefined variable: %s", name)
+ return zero
+}
+
+var zero reflect.Value
+
+// errorf formats the error and terminates processing.
+func (s *state) errorf(format string, args ...interface{}) {
+ format = fmt.Sprintf("template: %s:%d: %s", s.tmpl.Name(), s.line, format)
+ panic(fmt.Errorf(format, args...))
+}
+
+// error terminates processing.
+func (s *state) error(err os.Error) {
+ s.errorf("%s", err)
+}
+
+// errRecover is the handler that turns panics into returns from the top
+// level of Parse.
+func errRecover(errp *os.Error) {
+ e := recover()
+ if e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ *errp = e.(os.Error)
+ }
+}
+
+// Execute applies a parsed template to the specified data object,
+// writing the output to wr.
+func (t *Template) Execute(wr io.Writer, data interface{}) (err os.Error) {
+ defer errRecover(&err)
+ value := reflect.ValueOf(data)
+ state := &state{
+ tmpl: t,
+ wr: wr,
+ line: 1,
+ vars: []variable{{"$", value}},
+ }
+ if t.Root == nil {
+ state.errorf("must be parsed before execution")
+ }
+ state.walk(value, t.Root)
+ return
+}
+
+// Walk functions step through the major pieces of the template structure,
+// generating output as they go.
+func (s *state) walk(dot reflect.Value, n parse.Node) {
+ switch n := n.(type) {
+ case *parse.ActionNode:
+ s.line = n.Line
+ // Do not pop variables so they persist until next end.
+ // Also, if the action declares variables, don't print the result.
+ val := s.evalPipeline(dot, n.Pipe)
+ if len(n.Pipe.Decl) == 0 {
+ s.printValue(n, val)
+ }
+ case *parse.IfNode:
+ s.line = n.Line
+ s.walkIfOrWith(parse.NodeIf, dot, n.Pipe, n.List, n.ElseList)
+ case *parse.ListNode:
+ for _, node := range n.Nodes {
+ s.walk(dot, node)
+ }
+ case *parse.RangeNode:
+ s.line = n.Line
+ s.walkRange(dot, n)
+ case *parse.TemplateNode:
+ s.line = n.Line
+ s.walkTemplate(dot, n)
+ case *parse.TextNode:
+ if _, err := s.wr.Write(n.Text); err != nil {
+ s.error(err)
+ }
+ case *parse.WithNode:
+ s.line = n.Line
+ s.walkIfOrWith(parse.NodeWith, dot, n.Pipe, n.List, n.ElseList)
+ default:
+ s.errorf("unknown node: %s", n)
+ }
+}
+
+// walkIfOrWith walks an 'if' or 'with' node. The two control structures
+// are identical in behavior except that 'with' sets dot.
+func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) {
+ defer s.pop(s.mark())
+ val := s.evalPipeline(dot, pipe)
+ truth, ok := isTrue(val)
+ if !ok {
+ s.errorf("if/with can't use %v", val)
+ }
+ if truth {
+ if typ == parse.NodeWith {
+ s.walk(val, list)
+ } else {
+ s.walk(dot, list)
+ }
+ } else if elseList != nil {
+ s.walk(dot, elseList)
+ }
+}
+
+// isTrue returns whether the value is 'true', in the sense of not the zero of its type,
+// and whether the value has a meaningful truth value.
+func isTrue(val reflect.Value) (truth, ok bool) {
+ if !val.IsValid() {
+ // Something like var x interface{}, never set. It's a form of nil.
+ return false, true
+ }
+ switch val.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ truth = val.Len() > 0
+ case reflect.Bool:
+ truth = val.Bool()
+ case reflect.Complex64, reflect.Complex128:
+ truth = val.Complex() != 0
+ case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
+ truth = !val.IsNil()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ truth = val.Int() != 0
+ case reflect.Float32, reflect.Float64:
+ truth = val.Float() != 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ truth = val.Uint() != 0
+ case reflect.Struct:
+ truth = true // Struct values are always true.
+ default:
+ return
+ }
+ return truth, true
+}
+
+func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
+ defer s.pop(s.mark())
+ val, _ := indirect(s.evalPipeline(dot, r.Pipe))
+ // mark top of stack before any variables in the body are pushed.
+ mark := s.mark()
+ oneIteration := func(index, elem reflect.Value) {
+ // Set top var (lexically the second if there are two) to the element.
+ if len(r.Pipe.Decl) > 0 {
+ s.setVar(1, elem)
+ }
+ // Set next var (lexically the first if there are two) to the index.
+ if len(r.Pipe.Decl) > 1 {
+ s.setVar(2, index)
+ }
+ s.walk(elem, r.List)
+ s.pop(mark)
+ }
+ switch val.Kind() {
+ case reflect.Array, reflect.Slice:
+ if val.Len() == 0 {
+ break
+ }
+ for i := 0; i < val.Len(); i++ {
+ oneIteration(reflect.ValueOf(i), val.Index(i))
+ }
+ return
+ case reflect.Map:
+ if val.Len() == 0 {
+ break
+ }
+ for _, key := range val.MapKeys() {
+ oneIteration(key, val.MapIndex(key))
+ }
+ return
+ case reflect.Chan:
+ if val.IsNil() {
+ break
+ }
+ i := 0
+ for ; ; i++ {
+ elem, ok := val.Recv()
+ if !ok {
+ break
+ }
+ oneIteration(reflect.ValueOf(i), elem)
+ }
+ if i == 0 {
+ break
+ }
+ return
+ case reflect.Invalid:
+ break // An invalid value is likely a nil map, etc. and acts like an empty map.
+ default:
+ s.errorf("range can't iterate over %v", val)
+ }
+ if r.ElseList != nil {
+ s.walk(dot, r.ElseList)
+ }
+}
+
+func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
+ set := s.tmpl.set
+ if set == nil {
+ s.errorf("no set defined in which to invoke template named %q", t.Name)
+ }
+ tmpl := set.tmpl[t.Name]
+ if tmpl == nil {
+ s.errorf("template %q not in set", t.Name)
+ }
+ // Variables declared by the pipeline persist.
+ dot = s.evalPipeline(dot, t.Pipe)
+ newState := *s
+ newState.tmpl = tmpl
+ // No dynamic scoping: template invocations inherit no variables.
+ newState.vars = []variable{{"$", dot}}
+ newState.walk(dot, tmpl.Root)
+}
+
+// Eval functions evaluate pipelines, commands, and their elements and extract
+// values from the data structure by examining fields, calling methods, and so on.
+// The printing of those values happens only through walk functions.
+
+// evalPipeline returns the value acquired by evaluating a pipeline. If the
+// pipeline has a variable declaration, the variable will be pushed on the
+// stack. Callers should therefore pop the stack after they are finished
+// executing commands depending on the pipeline value.
+func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value reflect.Value) {
+ if pipe == nil {
+ return
+ }
+ for _, cmd := range pipe.Cmds {
+ value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg.
+ // If the object has type interface{}, dig down one level to the thing inside.
+ if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 {
+ value = reflect.ValueOf(value.Interface()) // lovely!
+ }
+ }
+ for _, variable := range pipe.Decl {
+ s.push(variable.Ident[0], value)
+ }
+ return value
+}
+
+func (s *state) notAFunction(args []parse.Node, final reflect.Value) {
+ if len(args) > 1 || final.IsValid() {
+ s.errorf("can't give argument to non-function %s", args[0])
+ }
+}
+
+func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final reflect.Value) reflect.Value {
+ firstWord := cmd.Args[0]
+ switch n := firstWord.(type) {
+ case *parse.FieldNode:
+ return s.evalFieldNode(dot, n, cmd.Args, final)
+ case *parse.IdentifierNode:
+ // Must be a function.
+ return s.evalFunction(dot, n.Ident, cmd.Args, final)
+ case *parse.VariableNode:
+ return s.evalVariableNode(dot, n, cmd.Args, final)
+ }
+ s.notAFunction(cmd.Args, final)
+ switch word := firstWord.(type) {
+ case *parse.BoolNode:
+ return reflect.ValueOf(word.True)
+ case *parse.DotNode:
+ return dot
+ case *parse.NumberNode:
+ return s.idealConstant(word)
+ case *parse.StringNode:
+ return reflect.ValueOf(word.Text)
+ }
+ s.errorf("can't evaluate command %q", firstWord)
+ panic("not reached")
+}
+
+// idealConstant is called to return the value of a number in a context where
+// we don't know the type. In that case, the syntax of the number tells us
+// its type, and we use Go rules to resolve. Note there is no such thing as
+// a uint ideal constant in this situation - the value must be of int type.
+func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
+ // These are ideal constants but we don't know the type
+ // and we have no context. (If it was a method argument,
+ // we'd know what we need.) The syntax guides us to some extent.
+ switch {
+ case constant.IsComplex:
+ return reflect.ValueOf(constant.Complex128) // incontrovertible.
+ case constant.IsFloat && strings.IndexAny(constant.Text, ".eE") >= 0:
+ return reflect.ValueOf(constant.Float64)
+ case constant.IsInt:
+ n := int(constant.Int64)
+ if int64(n) != constant.Int64 {
+ s.errorf("%s overflows int", constant.Text)
+ }
+ return reflect.ValueOf(n)
+ case constant.IsUint:
+ s.errorf("%s overflows int", constant.Text)
+ }
+ return zero
+}
+
+func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []parse.Node, final reflect.Value) reflect.Value {
+ return s.evalFieldChain(dot, dot, field.Ident, args, final)
+}
+
+func (s *state) evalVariableNode(dot reflect.Value, v *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value {
+ // $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields.
+ value := s.varValue(v.Ident[0])
+ if len(v.Ident) == 1 {
+ return value
+ }
+ return s.evalFieldChain(dot, value, v.Ident[1:], args, final)
+}
+
+// evalFieldChain evaluates .X.Y.Z possibly followed by arguments.
+// dot is the environment in which to evaluate arguments, while
+// receiver is the value being walked along the chain.
+func (s *state) evalFieldChain(dot, receiver reflect.Value, ident []string, args []parse.Node, final reflect.Value) reflect.Value {
+ n := len(ident)
+ for i := 0; i < n-1; i++ {
+ receiver = s.evalField(dot, ident[i], nil, zero, receiver)
+ }
+ // Now if it's a method, it gets the arguments.
+ return s.evalField(dot, ident[n-1], args, final, receiver)
+}
+
+func (s *state) evalFunction(dot reflect.Value, name string, args []parse.Node, final reflect.Value) reflect.Value {
+ function, ok := findFunction(name, s.tmpl, s.tmpl.set)
+ if !ok {
+ s.errorf("%q is not a defined function", name)
+ }
+ return s.evalCall(dot, function, name, args, final)
+}
+
+// evalField evaluates an expression like (.Field) or (.Field arg1 arg2).
+// The 'final' argument represents the return value from the preceding
+// value of the pipeline, if any.
+func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node, final, receiver reflect.Value) reflect.Value {
+ if !receiver.IsValid() {
+ return zero
+ }
+ typ := receiver.Type()
+ receiver, _ = indirect(receiver)
+ // Unless it's an interface, need to get to a value of type *T to guarantee
+ // we see all methods of T and *T.
+ ptr := receiver
+ if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
+ ptr = ptr.Addr()
+ }
+ if method, ok := methodByName(ptr, fieldName); ok {
+ return s.evalCall(dot, method, fieldName, args, final)
+ }
+ hasArgs := len(args) > 1 || final.IsValid()
+ // It's not a method; is it a field of a struct?
+ receiver, isNil := indirect(receiver)
+ if receiver.Kind() == reflect.Struct {
+ tField, ok := receiver.Type().FieldByName(fieldName)
+ if ok {
+ field := receiver.FieldByIndex(tField.Index)
+ if hasArgs {
+ s.errorf("%s is not a method but has arguments", fieldName)
+ }
+ if tField.PkgPath == "" { // field is exported
+ return field
+ }
+ }
+ }
+ // If it's a map, attempt to use the field name as a key.
+ if receiver.Kind() == reflect.Map {
+ nameVal := reflect.ValueOf(fieldName)
+ if nameVal.Type().AssignableTo(receiver.Type().Key()) {
+ if hasArgs {
+ s.errorf("%s is not a method but has arguments", fieldName)
+ }
+ return receiver.MapIndex(nameVal)
+ }
+ }
+ if isNil {
+ s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
+ }
+ s.errorf("can't evaluate field %s in type %s", fieldName, typ)
+ panic("not reached")
+}
+
+// TODO: delete when reflect's own MethodByName is released.
+func methodByName(receiver reflect.Value, name string) (reflect.Value, bool) {
+ typ := receiver.Type()
+ for i := 0; i < typ.NumMethod(); i++ {
+ if typ.Method(i).Name == name {
+ return receiver.Method(i), true // This value includes the receiver.
+ }
+ }
+ return zero, false
+}
+
+var (
+ osErrorType = reflect.TypeOf((*os.Error)(nil)).Elem()
+ fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+)
+
+// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
+// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
+// as the function itself.
+func (s *state) evalCall(dot, fun reflect.Value, name string, args []parse.Node, final reflect.Value) reflect.Value {
+ if args != nil {
+ args = args[1:] // Zeroth arg is function name/node; not passed to function.
+ }
+ typ := fun.Type()
+ numIn := len(args)
+ if final.IsValid() {
+ numIn++
+ }
+ numFixed := len(args)
+ if typ.IsVariadic() {
+ numFixed = typ.NumIn() - 1 // last arg is the variadic one.
+ if numIn < numFixed {
+ s.errorf("wrong number of args for %s: want at least %d got %d", name, typ.NumIn()-1, len(args))
+ }
+ } else if numIn < typ.NumIn()-1 || !typ.IsVariadic() && numIn != typ.NumIn() {
+ s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), len(args))
+ }
+ if !goodFunc(typ) {
+ s.errorf("can't handle multiple results from method/function %q", name)
+ }
+ // Build the arg list.
+ argv := make([]reflect.Value, numIn)
+ // Args must be evaluated. Fixed args first.
+ i := 0
+ for ; i < numFixed; i++ {
+ argv[i] = s.evalArg(dot, typ.In(i), args[i])
+ }
+ // Now the ... args.
+ if typ.IsVariadic() {
+ argType := typ.In(typ.NumIn() - 1).Elem() // Argument is a slice.
+ for ; i < len(args); i++ {
+ argv[i] = s.evalArg(dot, argType, args[i])
+ }
+ }
+ // Add final value if necessary.
+ if final.IsValid() {
+ argv[i] = final
+ }
+ result := fun.Call(argv)
+ // If we have an os.Error that is not nil, stop execution and return that error to the caller.
+ if len(result) == 2 && !result[1].IsNil() {
+ s.errorf("error calling %s: %s", name, result[1].Interface().(os.Error))
+ }
+ return result[0]
+}
+
+// validateType guarantees that the value is valid and assignable to the type.
+func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value {
+ if !value.IsValid() {
+ s.errorf("invalid value; expected %s", typ)
+ }
+ if !value.Type().AssignableTo(typ) {
+ // Does one dereference or indirection work? We could do more, as we
+ // do with method receivers, but that gets messy and method receivers
+ // are much more constrained, so it makes more sense there than here.
+ // Besides, one is almost always all you need.
+ switch {
+ case value.Kind() == reflect.Ptr && value.Elem().Type().AssignableTo(typ):
+ value = value.Elem()
+ case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
+ value = value.Addr()
+ default:
+ s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
+ }
+ }
+ return value
+}
+
+func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) reflect.Value {
+ switch arg := n.(type) {
+ case *parse.DotNode:
+ return s.validateType(dot, typ)
+ case *parse.FieldNode:
+ return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, zero), typ)
+ case *parse.VariableNode:
+ return s.validateType(s.evalVariableNode(dot, arg, nil, zero), typ)
+ }
+ switch typ.Kind() {
+ case reflect.Bool:
+ return s.evalBool(typ, n)
+ case reflect.Complex64, reflect.Complex128:
+ return s.evalComplex(typ, n)
+ case reflect.Float32, reflect.Float64:
+ return s.evalFloat(typ, n)
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return s.evalInteger(typ, n)
+ case reflect.Interface:
+ if typ.NumMethod() == 0 {
+ return s.evalEmptyInterface(dot, n)
+ }
+ case reflect.String:
+ return s.evalString(typ, n)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return s.evalUnsignedInteger(typ, n)
+ }
+ s.errorf("can't handle %s for arg of type %s", n, typ)
+ panic("not reached")
+}
+
+func (s *state) evalBool(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.BoolNode); ok {
+ value := reflect.New(typ).Elem()
+ value.SetBool(n.True)
+ return value
+ }
+ s.errorf("expected bool; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalString(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.StringNode); ok {
+ value := reflect.New(typ).Elem()
+ value.SetString(n.Text)
+ return value
+ }
+ s.errorf("expected string; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalInteger(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.NumberNode); ok && n.IsInt {
+ value := reflect.New(typ).Elem()
+ value.SetInt(n.Int64)
+ return value
+ }
+ s.errorf("expected integer; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalUnsignedInteger(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.NumberNode); ok && n.IsUint {
+ value := reflect.New(typ).Elem()
+ value.SetUint(n.Uint64)
+ return value
+ }
+ s.errorf("expected unsigned integer; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalFloat(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.NumberNode); ok && n.IsFloat {
+ value := reflect.New(typ).Elem()
+ value.SetFloat(n.Float64)
+ return value
+ }
+ s.errorf("expected float; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalComplex(typ reflect.Type, n parse.Node) reflect.Value {
+ if n, ok := n.(*parse.NumberNode); ok && n.IsComplex {
+ value := reflect.New(typ).Elem()
+ value.SetComplex(n.Complex128)
+ return value
+ }
+ s.errorf("expected complex; found %s", n)
+ panic("not reached")
+}
+
+func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Value {
+ switch n := n.(type) {
+ case *parse.BoolNode:
+ return reflect.ValueOf(n.True)
+ case *parse.DotNode:
+ return dot
+ case *parse.FieldNode:
+ return s.evalFieldNode(dot, n, nil, zero)
+ case *parse.IdentifierNode:
+ return s.evalFunction(dot, n.Ident, nil, zero)
+ case *parse.NumberNode:
+ return s.idealConstant(n)
+ case *parse.StringNode:
+ return reflect.ValueOf(n.Text)
+ case *parse.VariableNode:
+ return s.evalVariableNode(dot, n, nil, zero)
+ }
+ s.errorf("can't handle assignment of %s to empty interface argument", n)
+ panic("not reached")
+}
+
+// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
+// We indirect through pointers and empty interfaces (only) because
+// non-empty interfaces have methods we might need.
+func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
+ for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
+ if v.IsNil() {
+ return v, true
+ }
+ if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
+ break
+ }
+ }
+ return v, false
+}
+
+// printValue writes the textual representation of the value to the output of
+// the template.
+func (s *state) printValue(n parse.Node, v reflect.Value) {
+ if v.Kind() == reflect.Ptr {
+ v, _ = indirect(v) // fmt.Fprint handles nil.
+ }
+ if !v.IsValid() {
+ fmt.Fprint(s.wr, "<no value>")
+ return
+ }
+
+ if !v.Type().Implements(fmtStringerType) {
+ if v.CanAddr() && reflect.PtrTo(v.Type()).Implements(fmtStringerType) {
+ v = v.Addr()
+ } else {
+ switch v.Kind() {
+ case reflect.Chan, reflect.Func:
+ s.errorf("can't print %s of type %s", n, v.Type())
+ }
+ }
+ }
+ fmt.Fprint(s.wr, v.Interface())
+}
diff --git a/libgo/go/template/exec_test.go b/libgo/go/template/exec_test.go
new file mode 100644
index 00000000000..8e1894ea03b
--- /dev/null
+++ b/libgo/go/template/exec_test.go
@@ -0,0 +1,613 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "os"
+ "reflect"
+ "sort"
+ "strings"
+ "testing"
+)
+
+var debug = flag.Bool("debug", false, "show the errors produced by the tests")
+
+// T has lots of interesting pieces to use to test execution.
+type T struct {
+ // Basics
+ True bool
+ I int
+ U16 uint16
+ X string
+ FloatZero float64
+ ComplexZero float64
+ // Nested structs.
+ U *U
+ // Struct with String method.
+ V0 V
+ V1, V2 *V
+ // Slices
+ SI []int
+ SIEmpty []int
+ SB []bool
+ // Maps
+ MSI map[string]int
+ MSIone map[string]int // one element, for deterministic output
+ MSIEmpty map[string]int
+ MXI map[interface{}]int
+ MII map[int]int
+ SMSI []map[string]int
+ // Empty interfaces; used to see if we can dig inside one.
+ Empty0 interface{} // nil
+ Empty1 interface{}
+ Empty2 interface{}
+ Empty3 interface{}
+ Empty4 interface{}
+ // Non-empty interface.
+ NonEmptyInterface I
+ // Stringer.
+ Str fmt.Stringer
+ // Pointers
+ PI *int
+ PSI *[]int
+ NIL *int
+ // Template to test evaluation of templates.
+ Tmpl *Template
+}
+
+type U struct {
+ V string
+}
+
+type V struct {
+ j int
+}
+
+func (v *V) String() string {
+ if v == nil {
+ return "nilV"
+ }
+ return fmt.Sprintf("<%d>", v.j)
+}
+
+var tVal = &T{
+ True: true,
+ I: 17,
+ U16: 16,
+ X: "x",
+ U: &U{"v"},
+ V0: V{6666},
+ V1: &V{7777}, // leave V2 as nil
+ SI: []int{3, 4, 5},
+ SB: []bool{true, false},
+ MSI: map[string]int{"one": 1, "two": 2, "three": 3},
+ MSIone: map[string]int{"one": 1},
+ MXI: map[interface{}]int{"one": 1},
+ MII: map[int]int{1: 1},
+ SMSI: []map[string]int{
+ {"one": 1, "two": 2},
+ {"eleven": 11, "twelve": 12},
+ },
+ Empty1: 3,
+ Empty2: "empty2",
+ Empty3: []int{7, 8},
+ Empty4: &U{"UinEmpty"},
+ NonEmptyInterface: new(T),
+ Str: os.NewError("foozle"),
+ PI: newInt(23),
+ PSI: newIntSlice(21, 22, 23),
+ Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
+}
+
+// A non-empty interface.
+type I interface {
+ Method0() string
+}
+
+var iVal I = tVal
+
+// Helpers for creation.
+func newInt(n int) *int {
+ p := new(int)
+ *p = n
+ return p
+}
+
+func newIntSlice(n ...int) *[]int {
+ p := new([]int)
+ *p = make([]int, len(n))
+ copy(*p, n)
+ return p
+}
+
+// Simple methods with and without arguments.
+func (t *T) Method0() string {
+ return "M0"
+}
+
+func (t *T) Method1(a int) int {
+ return a
+}
+
+func (t *T) Method2(a uint16, b string) string {
+ return fmt.Sprintf("Method2: %d %s", a, b)
+}
+
+func (t *T) MAdd(a int, b []int) []int {
+ v := make([]int, len(b))
+ for i, x := range b {
+ v[i] = x + a
+ }
+ return v
+}
+
+// MSort is used to sort map keys for stable output. (Nice trick!)
+func (t *T) MSort(m map[string]int) []string {
+ keys := make([]string, len(m))
+ i := 0
+ for k := range m {
+ keys[i] = k
+ i++
+ }
+ sort.Strings(keys)
+ return keys
+}
+
+// EPERM returns a value and an os.Error according to its argument.
+func (t *T) EPERM(error bool) (bool, os.Error) {
+ if error {
+ return true, os.EPERM
+ }
+ return false, nil
+}
+
+// A few methods to test chaining.
+func (t *T) GetU() *U {
+ return t.U
+}
+
+func (u *U) TrueFalse(b bool) string {
+ if b {
+ return "true"
+ }
+ return ""
+}
+
+func typeOf(arg interface{}) string {
+ return fmt.Sprintf("%T", arg)
+}
+
+type execTest struct {
+ name string
+ input string
+ output string
+ data interface{}
+ ok bool
+}
+
+// bigInt and bigUint are hex string representing numbers either side
+// of the max int boundary.
+// We do it this way so the test doesn't depend on ints being 32 bits.
+var (
+ bigInt = fmt.Sprintf("0x%x", int(1<<uint(reflect.TypeOf(0).Bits()-1)-1))
+ bigUint = fmt.Sprintf("0x%x", uint(1<<uint(reflect.TypeOf(0).Bits()-1)))
+)
+
+var execTests = []execTest{
+ // Trivial cases.
+ {"empty", "", "", nil, true},
+ {"text", "some text", "some text", nil, true},
+
+ // Ideal constants.
+ {"ideal int", "{{typeOf 3}}", "int", 0, true},
+ {"ideal float", "{{typeOf 1.0}}", "float64", 0, true},
+ {"ideal exp float", "{{typeOf 1e1}}", "float64", 0, true},
+ {"ideal complex", "{{typeOf 1i}}", "complex128", 0, true},
+ {"ideal int", "{{typeOf " + bigInt + "}}", "int", 0, true},
+ {"ideal too big", "{{typeOf " + bigUint + "}}", "", 0, false},
+
+ // Fields of structs.
+ {".X", "-{{.X}}-", "-x-", tVal, true},
+ {".U.V", "-{{.U.V}}-", "-v-", tVal, true},
+
+ // Fields on maps.
+ {"map .one", "{{.MSI.one}}", "1", tVal, true},
+ {"map .two", "{{.MSI.two}}", "2", tVal, true},
+ {"map .NO", "{{.MSI.NO}}", "<no value>", tVal, true},
+ {"map .one interface", "{{.MXI.one}}", "1", tVal, true},
+ {"map .WRONG args", "{{.MSI.one 1}}", "", tVal, false},
+ {"map .WRONG type", "{{.MII.one}}", "", tVal, false},
+
+ // Dots of all kinds to test basic evaluation.
+ {"dot int", "<{{.}}>", "<13>", 13, true},
+ {"dot uint", "<{{.}}>", "<14>", uint(14), true},
+ {"dot float", "<{{.}}>", "<15.1>", 15.1, true},
+ {"dot bool", "<{{.}}>", "<true>", true, true},
+ {"dot complex", "<{{.}}>", "<(16.2-17i)>", 16.2 - 17i, true},
+ {"dot string", "<{{.}}>", "<hello>", "hello", true},
+ {"dot slice", "<{{.}}>", "<[-1 -2 -3]>", []int{-1, -2, -3}, true},
+ {"dot map", "<{{.}}>", "<map[two:22 one:11]>", map[string]int{"one": 11, "two": 22}, true},
+ {"dot struct", "<{{.}}>", "<{7 seven}>", struct {
+ a int
+ b string
+ }{7, "seven"}, true},
+
+ // Variables.
+ {"$ int", "{{$}}", "123", 123, true},
+ {"$.I", "{{$.I}}", "17", tVal, true},
+ {"$.U.V", "{{$.U.V}}", "v", tVal, true},
+ {"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
+
+ // Type with String method.
+ {"V{6666}.String()", "-{{.V0}}-", "-<6666>-", tVal, true},
+ {"&V{7777}.String()", "-{{.V1}}-", "-<7777>-", tVal, true},
+ {"(*V)(nil).String()", "-{{.V2}}-", "-nilV-", tVal, true},
+
+ // Pointers.
+ {"*int", "{{.PI}}", "23", tVal, true},
+ {"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},
+ {"*[]int[1]", "{{index .PSI 1}}", "22", tVal, true},
+ {"NIL", "{{.NIL}}", "<nil>", tVal, true},
+
+ // Empty interfaces holding values.
+ {"empty nil", "{{.Empty0}}", "<no value>", tVal, true},
+ {"empty with int", "{{.Empty1}}", "3", tVal, true},
+ {"empty with string", "{{.Empty2}}", "empty2", tVal, true},
+ {"empty with slice", "{{.Empty3}}", "[7 8]", tVal, true},
+ {"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true},
+ {"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true},
+
+ // Method calls.
+ {".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
+ {".Method1(1234)", "-{{.Method1 1234}}-", "-1234-", tVal, true},
+ {".Method1(.I)", "-{{.Method1 .I}}-", "-17-", tVal, true},
+ {".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
+ {".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
+ {".Method2(.U16, $x)", "{{if $x := .X}}-{{.Method2 .U16 $x}}{{end}}-", "-Method2: 16 x-", tVal, true},
+ {"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
+ {"method on chained var",
+ "{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
+ "true", tVal, true},
+ {"chained method",
+ "{{range .MSIone}}{{if $.GetU.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
+ "true", tVal, true},
+ {"chained method on variable",
+ "{{with $x := .}}{{with .SI}}{{$.GetU.TrueFalse $.True}}{{end}}{{end}}",
+ "true", tVal, true},
+
+ // Pipelines.
+ {"pipeline", "-{{.Method0 | .Method2 .U16}}-", "-Method2: 16 M0-", tVal, true},
+
+ // If.
+ {"if true", "{{if true}}TRUE{{end}}", "TRUE", tVal, true},
+ {"if false", "{{if false}}TRUE{{else}}FALSE{{end}}", "FALSE", tVal, true},
+ {"if 1", "{{if 1}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+ {"if 0", "{{if 0}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"if 1.5", "{{if 1.5}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+ {"if 0.0", "{{if .FloatZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"if 1.5i", "{{if 1.5i}}NON-ZERO{{else}}ZERO{{end}}", "NON-ZERO", tVal, true},
+ {"if 0.0i", "{{if .ComplexZero}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"if emptystring", "{{if ``}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"if string", "{{if `notempty`}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+ {"if emptyslice", "{{if .SIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"if slice", "{{if .SI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+ {"if emptymap", "{{if .MSIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"if map", "{{if .MSI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+ {"if $x with $y int", "{{if $x := true}}{{with $y := .I}}{{$x}},{{$y}}{{end}}{{end}}", "true,17", tVal, true},
+ {"if $x with $x int", "{{if $x := true}}{{with $x := .I}}{{$x}},{{end}}{{$x}}{{end}}", "17,true", tVal, true},
+
+ // Print etc.
+ {"print", `{{print "hello, print"}}`, "hello, print", tVal, true},
+ {"print", `{{print 1 2 3}}`, "1 2 3", tVal, true},
+ {"println", `{{println 1 2 3}}`, "1 2 3\n", tVal, true},
+ {"printf int", `{{printf "%04x" 127}}`, "007f", tVal, true},
+ {"printf float", `{{printf "%g" 3.5}}`, "3.5", tVal, true},
+ {"printf complex", `{{printf "%g" 1+7i}}`, "(1+7i)", tVal, true},
+ {"printf string", `{{printf "%s" "hello"}}`, "hello", tVal, true},
+ {"printf function", `{{printf "%#q" zeroArgs}}`, "`zeroArgs`", tVal, true},
+ {"printf field", `{{printf "%s" .U.V}}`, "v", tVal, true},
+ {"printf method", `{{printf "%s" .Method0}}`, "M0", tVal, true},
+ {"printf dot", `{{with .I}}{{printf "%d" .}}{{end}}`, "17", tVal, true},
+ {"printf var", `{{with $x := .I}}{{printf "%d" $x}}{{end}}`, "17", tVal, true},
+ {"printf lots", `{{printf "%d %s %g %s" 127 "hello" 7-3i .Method0}}`, "127 hello (7-3i) M0", tVal, true},
+
+ // HTML.
+ {"html", `{{html "<script>alert(\"XSS\");</script>"}}`,
+ "&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
+ {"html pipeline", `{{printf "<script>alert(\"XSS\");</script>" | html}}`,
+ "&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;", nil, true},
+
+ // JavaScript.
+ {"js", `{{js .}}`, `It\'d be nice.`, `It'd be nice.`, true},
+
+ // URL query.
+ {"urlquery", `{{"http://www.example.org/"|urlquery}}`, "http%3A%2F%2Fwww.example.org%2F", nil, true},
+
+ // Booleans
+ {"not", "{{not true}} {{not false}}", "false true", nil, true},
+ {"and", "{{and false 0}} {{and 1 0}} {{and 0 true}} {{and 1 1}}", "false 0 0 1", nil, true},
+ {"or", "{{or 0 0}} {{or 1 0}} {{or 0 true}} {{or 1 1}}", "0 1 true 1", nil, true},
+ {"boolean if", "{{if and true 1 `hi`}}TRUE{{else}}FALSE{{end}}", "TRUE", tVal, true},
+ {"boolean if not", "{{if and true 1 `hi` | not}}TRUE{{else}}FALSE{{end}}", "FALSE", nil, true},
+
+ // Indexing.
+ {"slice[0]", "{{index .SI 0}}", "3", tVal, true},
+ {"slice[1]", "{{index .SI 1}}", "4", tVal, true},
+ {"slice[HUGE]", "{{index .SI 10}}", "", tVal, false},
+ {"slice[WRONG]", "{{index .SI `hello`}}", "", tVal, false},
+ {"map[one]", "{{index .MSI `one`}}", "1", tVal, true},
+ {"map[two]", "{{index .MSI `two`}}", "2", tVal, true},
+ {"map[NO]", "{{index .MSI `XXX`}}", "", tVal, true},
+ {"map[WRONG]", "{{index .MSI 10}}", "", tVal, false},
+ {"double index", "{{index .SMSI 1 `eleven`}}", "11", tVal, true},
+
+ // Len.
+ {"slice", "{{len .SI}}", "3", tVal, true},
+ {"map", "{{len .MSI }}", "3", tVal, true},
+ {"len of int", "{{len 3}}", "", tVal, false},
+ {"len of nothing", "{{len .Empty0}}", "", tVal, false},
+
+ // With.
+ {"with true", "{{with true}}{{.}}{{end}}", "true", tVal, true},
+ {"with false", "{{with false}}{{.}}{{else}}FALSE{{end}}", "FALSE", tVal, true},
+ {"with 1", "{{with 1}}{{.}}{{else}}ZERO{{end}}", "1", tVal, true},
+ {"with 0", "{{with 0}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"with 1.5", "{{with 1.5}}{{.}}{{else}}ZERO{{end}}", "1.5", tVal, true},
+ {"with 0.0", "{{with .FloatZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"with 1.5i", "{{with 1.5i}}{{.}}{{else}}ZERO{{end}}", "(0+1.5i)", tVal, true},
+ {"with 0.0i", "{{with .ComplexZero}}{{.}}{{else}}ZERO{{end}}", "ZERO", tVal, true},
+ {"with emptystring", "{{with ``}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"with string", "{{with `notempty`}}{{.}}{{else}}EMPTY{{end}}", "notempty", tVal, true},
+ {"with emptyslice", "{{with .SIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"with slice", "{{with .SI}}{{.}}{{else}}EMPTY{{end}}", "[3 4 5]", tVal, true},
+ {"with emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"with map", "{{with .MSIone}}{{.}}{{else}}EMPTY{{end}}", "map[one:1]", tVal, true},
+ {"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "UinEmpty", tVal, true},
+ {"with $x int", "{{with $x := .I}}{{$x}}{{end}}", "17", tVal, true},
+ {"with $x struct.U.V", "{{with $x := $}}{{$x.U.V}}{{end}}", "v", tVal, true},
+ {"with variable and action", "{{with $x := $}}{{$y := $.U.V}}{{$y}}{{end}}", "v", tVal, true},
+
+ // Range.
+ {"range []int", "{{range .SI}}-{{.}}-{{end}}", "-3--4--5-", tVal, true},
+ {"range empty no else", "{{range .SIEmpty}}-{{.}}-{{end}}", "", tVal, true},
+ {"range []int else", "{{range .SI}}-{{.}}-{{else}}EMPTY{{end}}", "-3--4--5-", tVal, true},
+ {"range empty else", "{{range .SIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"range []bool", "{{range .SB}}-{{.}}-{{end}}", "-true--false-", tVal, true},
+ {"range []int method", "{{range .SI | .MAdd .I}}-{{.}}-{{end}}", "-20--21--22-", tVal, true},
+ {"range map", "{{range .MSI | .MSort}}-{{.}}-{{end}}", "-one--three--two-", tVal, true},
+ {"range empty map no else", "{{range .MSIEmpty}}-{{.}}-{{end}}", "", tVal, true},
+ {"range map else", "{{range .MSI | .MSort}}-{{.}}-{{else}}EMPTY{{end}}", "-one--three--two-", tVal, true},
+ {"range empty map else", "{{range .MSIEmpty}}-{{.}}-{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
+ {"range empty interface", "{{range .Empty3}}-{{.}}-{{else}}EMPTY{{end}}", "-7--8-", tVal, true},
+ {"range empty nil", "{{range .Empty0}}-{{.}}-{{end}}", "", tVal, true},
+ {"range $x SI", "{{range $x := .SI}}<{{$x}}>{{end}}", "<3><4><5>", tVal, true},
+ {"range $x $y SI", "{{range $x, $y := .SI}}<{{$x}}={{$y}}>{{end}}", "<0=3><1=4><2=5>", tVal, true},
+ {"range $x MSIone", "{{range $x := .MSIone}}<{{$x}}>{{end}}", "<1>", tVal, true},
+ {"range $x $y MSIone", "{{range $x, $y := .MSIone}}<{{$x}}={{$y}}>{{end}}", "<one=1>", tVal, true},
+ {"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "<21><22><23>", tVal, true},
+ {"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
+ {"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true},
+ {"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true},
+
+ // Cute examples.
+ {"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
+ {"or as if false", `{{or .SIEmpty "slice is empty"}}`, "slice is empty", tVal, true},
+
+ // Error handling.
+ {"error method, error", "{{.EPERM true}}", "", tVal, false},
+ {"error method, no error", "{{.EPERM false}}", "false", tVal, true},
+
+ // Fixed bugs.
+ // Must separate dot and receiver; otherwise args are evaluated with dot set to variable.
+ {"bug0", "{{range .MSIone}}{{if $.Method1 .}}X{{end}}{{end}}", "X", tVal, true},
+ // Do not loop endlessly in indirect for non-empty interfaces.
+ // The bug appears with *interface only; looped forever.
+ {"bug1", "{{.Method0}}", "M0", &iVal, true},
+ // Was taking address of interface field, so method set was empty.
+ {"bug2", "{{$.NonEmptyInterface.Method0}}", "M0", tVal, true},
+ // Struct values were not legal in with - mere oversight.
+ {"bug3", "{{with $}}{{.Method0}}{{end}}", "M0", tVal, true},
+ // Nil interface values in if.
+ {"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
+ // Stringer.
+ {"bug5", "{{.Str}}", "foozle", tVal, true},
+ // Args need to be indirected and dereferenced sometimes.
+ {"bug6a", "{{vfunc .V0 .V1}}", "vfunc", tVal, true},
+ {"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true},
+ {"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true},
+ {"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true},
+}
+
+func zeroArgs() string {
+ return "zeroArgs"
+}
+
+func oneArg(a string) string {
+ return "oneArg=" + a
+}
+
+// count returns a channel that will deliver n sequential 1-letter strings starting at "a"
+func count(n int) chan string {
+ if n == 0 {
+ return nil
+ }
+ c := make(chan string)
+ go func() {
+ for i := 0; i < n; i++ {
+ c <- "abcdefghijklmnop"[i : i+1]
+ }
+ close(c)
+ }()
+ return c
+}
+
+// vfunc takes a *V and a V
+func vfunc(V, *V) string {
+ return "vfunc"
+}
+
+func testExecute(execTests []execTest, set *Set, t *testing.T) {
+ b := new(bytes.Buffer)
+ funcs := FuncMap{
+ "count": count,
+ "oneArg": oneArg,
+ "typeOf": typeOf,
+ "vfunc": vfunc,
+ "zeroArgs": zeroArgs,
+ }
+ for _, test := range execTests {
+ tmpl := New(test.name).Funcs(funcs)
+ _, err := tmpl.ParseInSet(test.input, set)
+ if err != nil {
+ t.Errorf("%s: parse error: %s", test.name, err)
+ continue
+ }
+ b.Reset()
+ err = tmpl.Execute(b, test.data)
+ switch {
+ case !test.ok && err == nil:
+ t.Errorf("%s: expected error; got none", test.name)
+ continue
+ case test.ok && err != nil:
+ t.Errorf("%s: unexpected execute error: %s", test.name, err)
+ continue
+ case !test.ok && err != nil:
+ // expected error, got one
+ if *debug {
+ fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+ }
+ }
+ result := b.String()
+ if result != test.output {
+ t.Errorf("%s: expected\n\t%q\ngot\n\t%q", test.name, test.output, result)
+ }
+ }
+}
+
+func TestExecute(t *testing.T) {
+ testExecute(execTests, nil, t)
+}
+
+// Check that an error from a method flows back to the top.
+func TestExecuteError(t *testing.T) {
+ b := new(bytes.Buffer)
+ tmpl := New("error")
+ _, err := tmpl.Parse("{{.EPERM true}}")
+ if err != nil {
+ t.Fatalf("parse error: %s", err)
+ }
+ err = tmpl.Execute(b, tVal)
+ if err == nil {
+ t.Errorf("expected error; got none")
+ } else if !strings.Contains(err.String(), os.EPERM.String()) {
+ if *debug {
+ fmt.Printf("test execute error: %s\n", err)
+ }
+ t.Errorf("expected os.EPERM; got %s", err)
+ }
+}
+
+func TestJSEscaping(t *testing.T) {
+ testCases := []struct {
+ in, exp string
+ }{
+ {`a`, `a`},
+ {`'foo`, `\'foo`},
+ {`Go "jump" \`, `Go \"jump\" \\`},
+ {`Yukihiro says "今日は世界"`, `Yukihiro says \"今日は世界\"`},
+ {"unprintable \uFDFF", `unprintable \uFDFF`},
+ {`<html>`, `\x3Chtml\x3E`},
+ }
+ for _, tc := range testCases {
+ s := JSEscapeString(tc.in)
+ if s != tc.exp {
+ t.Errorf("JS escaping [%s] got [%s] want [%s]", tc.in, s, tc.exp)
+ }
+ }
+}
+
+// A nice example: walk a binary tree.
+
+type Tree struct {
+ Val int
+ Left, Right *Tree
+}
+
+const treeTemplate = `
+ {{define "tree"}}
+ [
+ {{.Val}}
+ {{with .Left}}
+ {{template "tree" .}}
+ {{end}}
+ {{with .Right}}
+ {{template "tree" .}}
+ {{end}}
+ ]
+ {{end}}
+`
+
+func TestTree(t *testing.T) {
+ var tree = &Tree{
+ 1,
+ &Tree{
+ 2, &Tree{
+ 3,
+ &Tree{
+ 4, nil, nil,
+ },
+ nil,
+ },
+ &Tree{
+ 5,
+ &Tree{
+ 6, nil, nil,
+ },
+ nil,
+ },
+ },
+ &Tree{
+ 7,
+ &Tree{
+ 8,
+ &Tree{
+ 9, nil, nil,
+ },
+ nil,
+ },
+ &Tree{
+ 10,
+ &Tree{
+ 11, nil, nil,
+ },
+ nil,
+ },
+ },
+ }
+ set := new(Set)
+ _, err := set.Parse(treeTemplate)
+ if err != nil {
+ t.Fatal("parse error:", err)
+ }
+ var b bytes.Buffer
+ err = set.Execute(&b, "tree", tree)
+ if err != nil {
+ t.Fatal("exec error:", err)
+ }
+ stripSpace := func(r int) int {
+ if r == '\t' || r == '\n' {
+ return -1
+ }
+ return r
+ }
+ result := strings.Map(stripSpace, b.String())
+ const expect = "[1[2[3[4]][5[6]]][7[8[9]][10[11]]]]"
+ if result != expect {
+ t.Errorf("expected %q got %q", expect, result)
+ }
+}
diff --git a/libgo/go/template/funcs.go b/libgo/go/template/funcs.go
new file mode 100644
index 00000000000..feb1fd82c72
--- /dev/null
+++ b/libgo/go/template/funcs.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 template
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "unicode"
+ "url"
+ "utf8"
+)
+
+// FuncMap is the type of the map defining the mapping from names to functions.
+// Each function must have either a single return value, or two return values of
+// which the second has type os.Error. If the second argument evaluates to non-nil
+// during execution, execution terminates and Execute returns an error.
+type FuncMap map[string]interface{}
+
+var builtins = FuncMap{
+ "and": and,
+ "html": HTMLEscaper,
+ "index": index,
+ "js": JSEscaper,
+ "len": length,
+ "not": not,
+ "or": or,
+ "print": fmt.Sprint,
+ "printf": fmt.Sprintf,
+ "println": fmt.Sprintln,
+ "urlquery": URLQueryEscaper,
+}
+
+var builtinFuncs = createValueFuncs(builtins)
+
+// createValueFuncs turns a FuncMap into a map[string]reflect.Value
+func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
+ m := make(map[string]reflect.Value)
+ addValueFuncs(m, funcMap)
+ return m
+}
+
+// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
+func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
+ for name, fn := range in {
+ v := reflect.ValueOf(fn)
+ if v.Kind() != reflect.Func {
+ panic("value for " + name + " not a function")
+ }
+ if !goodFunc(v.Type()) {
+ panic(fmt.Errorf("can't handle multiple results from method/function %q", name))
+ }
+ out[name] = v
+ }
+}
+
+// addFuncs adds to values the functions in funcs. It does no checking of the input -
+// call addValueFuncs first.
+func addFuncs(out, in FuncMap) {
+ for name, fn := range in {
+ out[name] = fn
+ }
+}
+
+// goodFunc checks that the function or method has the right result signature.
+func goodFunc(typ reflect.Type) bool {
+ // We allow functions with 1 result or 2 results where the second is an os.Error.
+ switch {
+ case typ.NumOut() == 1:
+ return true
+ case typ.NumOut() == 2 && typ.Out(1) == osErrorType:
+ return true
+ }
+ return false
+}
+
+// findFunction looks for a function in the template, set, and global map.
+func findFunction(name string, tmpl *Template, set *Set) (reflect.Value, bool) {
+ if tmpl != nil {
+ if fn := tmpl.execFuncs[name]; fn.IsValid() {
+ return fn, true
+ }
+ }
+ if set != nil {
+ if fn := set.execFuncs[name]; fn.IsValid() {
+ return fn, true
+ }
+ }
+ if fn := builtinFuncs[name]; fn.IsValid() {
+ return fn, true
+ }
+ return reflect.Value{}, false
+}
+
+// Indexing.
+
+// index returns the result of indexing its first argument by the following
+// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
+// indexed item must be a map, slice, or array.
+func index(item interface{}, indices ...interface{}) (interface{}, os.Error) {
+ v := reflect.ValueOf(item)
+ for _, i := range indices {
+ index := reflect.ValueOf(i)
+ var isNil bool
+ if v, isNil = indirect(v); isNil {
+ return nil, fmt.Errorf("index of nil pointer")
+ }
+ switch v.Kind() {
+ case reflect.Array, reflect.Slice:
+ var x int64
+ switch index.Kind() {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ x = index.Int()
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ x = int64(index.Uint())
+ default:
+ return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
+ }
+ if x < 0 || x >= int64(v.Len()) {
+ return nil, fmt.Errorf("index out of range: %d", x)
+ }
+ v = v.Index(int(x))
+ case reflect.Map:
+ if !index.Type().AssignableTo(v.Type().Key()) {
+ return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
+ }
+ if x := v.MapIndex(index); x.IsValid() {
+ v = x
+ } else {
+ v = reflect.Zero(v.Type().Key())
+ }
+ default:
+ return nil, fmt.Errorf("can't index item of type %s", index.Type())
+ }
+ }
+ return v.Interface(), nil
+}
+
+// Length
+
+// length returns the length of the item, with an error if it has no defined length.
+func length(item interface{}) (int, os.Error) {
+ v, isNil := indirect(reflect.ValueOf(item))
+ if isNil {
+ return 0, fmt.Errorf("len of nil pointer")
+ }
+ switch v.Kind() {
+ case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len(), nil
+ }
+ return 0, fmt.Errorf("len of type %s", v.Type())
+}
+
+// Boolean logic.
+
+func truth(a interface{}) bool {
+ t, _ := isTrue(reflect.ValueOf(a))
+ return t
+}
+
+// and computes the Boolean AND of its arguments, returning
+// the first false argument it encounters, or the last argument.
+func and(arg0 interface{}, args ...interface{}) interface{} {
+ if !truth(arg0) {
+ return arg0
+ }
+ for i := range args {
+ arg0 = args[i]
+ if !truth(arg0) {
+ break
+ }
+ }
+ return arg0
+}
+
+// or computes the Boolean OR of its arguments, returning
+// the first true argument it encounters, or the last argument.
+func or(arg0 interface{}, args ...interface{}) interface{} {
+ if truth(arg0) {
+ return arg0
+ }
+ for i := range args {
+ arg0 = args[i]
+ if truth(arg0) {
+ break
+ }
+ }
+ return arg0
+}
+
+// not returns the Boolean negation of its argument.
+func not(arg interface{}) (truth bool) {
+ truth, _ = isTrue(reflect.ValueOf(arg))
+ return !truth
+}
+
+// HTML escaping.
+
+var (
+ htmlQuot = []byte("&#34;") // shorter than "&quot;"
+ htmlApos = []byte("&#39;") // shorter than "&apos;"
+ htmlAmp = []byte("&amp;")
+ htmlLt = []byte("&lt;")
+ htmlGt = []byte("&gt;")
+)
+
+// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
+func HTMLEscape(w io.Writer, b []byte) {
+ last := 0
+ for i, c := range b {
+ var html []byte
+ switch c {
+ case '"':
+ html = htmlQuot
+ case '\'':
+ html = htmlApos
+ case '&':
+ html = htmlAmp
+ case '<':
+ html = htmlLt
+ case '>':
+ html = htmlGt
+ default:
+ continue
+ }
+ w.Write(b[last:i])
+ w.Write(html)
+ last = i + 1
+ }
+ w.Write(b[last:])
+}
+
+// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
+func HTMLEscapeString(s string) string {
+ // Avoid allocation if we can.
+ if strings.IndexAny(s, `'"&<>`) < 0 {
+ return s
+ }
+ var b bytes.Buffer
+ HTMLEscape(&b, []byte(s))
+ return b.String()
+}
+
+// HTMLEscaper returns the escaped HTML equivalent of the textual
+// representation of its arguments.
+func HTMLEscaper(args ...interface{}) string {
+ ok := false
+ var s string
+ if len(args) == 1 {
+ s, ok = args[0].(string)
+ }
+ if !ok {
+ s = fmt.Sprint(args...)
+ }
+ return HTMLEscapeString(s)
+}
+
+// JavaScript escaping.
+
+var (
+ jsLowUni = []byte(`\u00`)
+ hex = []byte("0123456789ABCDEF")
+
+ jsBackslash = []byte(`\\`)
+ jsApos = []byte(`\'`)
+ jsQuot = []byte(`\"`)
+ jsLt = []byte(`\x3C`)
+ jsGt = []byte(`\x3E`)
+)
+
+// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
+func JSEscape(w io.Writer, b []byte) {
+ last := 0
+ for i := 0; i < len(b); i++ {
+ c := b[i]
+
+ if !jsIsSpecial(int(c)) {
+ // fast path: nothing to do
+ continue
+ }
+ w.Write(b[last:i])
+
+ if c < utf8.RuneSelf {
+ // Quotes, slashes and angle brackets get quoted.
+ // Control characters get written as \u00XX.
+ switch c {
+ case '\\':
+ w.Write(jsBackslash)
+ case '\'':
+ w.Write(jsApos)
+ case '"':
+ w.Write(jsQuot)
+ case '<':
+ w.Write(jsLt)
+ case '>':
+ w.Write(jsGt)
+ default:
+ w.Write(jsLowUni)
+ t, b := c>>4, c&0x0f
+ w.Write(hex[t : t+1])
+ w.Write(hex[b : b+1])
+ }
+ } else {
+ // Unicode rune.
+ rune, size := utf8.DecodeRune(b[i:])
+ if unicode.IsPrint(rune) {
+ w.Write(b[i : i+size])
+ } else {
+ // TODO(dsymonds): Do this without fmt?
+ fmt.Fprintf(w, "\\u%04X", rune)
+ }
+ i += size - 1
+ }
+ last = i + 1
+ }
+ w.Write(b[last:])
+}
+
+// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
+func JSEscapeString(s string) string {
+ // Avoid allocation if we can.
+ if strings.IndexFunc(s, jsIsSpecial) < 0 {
+ return s
+ }
+ var b bytes.Buffer
+ JSEscape(&b, []byte(s))
+ return b.String()
+}
+
+func jsIsSpecial(rune int) bool {
+ switch rune {
+ case '\\', '\'', '"', '<', '>':
+ return true
+ }
+ return rune < ' ' || utf8.RuneSelf <= rune
+}
+
+// JSEscaper returns the escaped JavaScript equivalent of the textual
+// representation of its arguments.
+func JSEscaper(args ...interface{}) string {
+ ok := false
+ var s string
+ if len(args) == 1 {
+ s, ok = args[0].(string)
+ }
+ if !ok {
+ s = fmt.Sprint(args...)
+ }
+ return JSEscapeString(s)
+}
+
+// URLQueryEscaper returns the escaped value of the textual representation of
+// its arguments in a form suitable for embedding in a URL query.
+func URLQueryEscaper(args ...interface{}) string {
+ s, ok := "", false
+ if len(args) == 1 {
+ s, ok = args[0].(string)
+ }
+ if !ok {
+ s = fmt.Sprint(args...)
+ }
+ return url.QueryEscape(s)
+}
diff --git a/libgo/go/template/helper.go b/libgo/go/template/helper.go
new file mode 100644
index 00000000000..c9b09985651
--- /dev/null
+++ b/libgo/go/template/helper.go
@@ -0,0 +1,238 @@
+// 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.
+
+// Helper functions to make constructing templates and sets easier.
+
+package template
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+// Functions and methods to parse a single template.
+
+// Must is a helper that wraps a call to a function returning (*Template, os.Error)
+// and panics if the error is non-nil. It is intended for use in variable initializations
+// such as
+// var t = template.Must(template.New("name").Parse("text"))
+func Must(t *Template, err os.Error) *Template {
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+// ParseFile creates a new Template and parses the template definition from
+// the named file. The template name is the base name of the file.
+func ParseFile(filename string) (*Template, os.Error) {
+ t := New(filepath.Base(filename))
+ return t.ParseFile(filename)
+}
+
+// parseFileInSet creates a new Template and parses the template
+// definition from the named file. The template name is the base name
+// of the file. It also adds the template to the set. Function bindings are
+// checked against those in the set.
+func parseFileInSet(filename string, set *Set) (*Template, os.Error) {
+ t := New(filepath.Base(filename))
+ return t.parseFileInSet(filename, set)
+}
+
+// ParseFile reads the template definition from a file and parses it to
+// construct an internal representation of the template for execution.
+// The returned template will be nil if an error occurs.
+func (t *Template) ParseFile(filename string) (*Template, os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return t.Parse(string(b))
+}
+
+// parseFileInSet is the same as ParseFile except that function bindings
+// are checked against those in the set and the template is added
+// to the set.
+// The returned template will be nil if an error occurs.
+func (t *Template) parseFileInSet(filename string, set *Set) (*Template, os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ return t.ParseInSet(string(b), set)
+}
+
+// Functions and methods to parse a set.
+
+// SetMust is a helper that wraps a call to a function returning (*Set, os.Error)
+// and panics if the error is non-nil. It is intended for use in variable initializations
+// such as
+// var s = template.SetMust(template.ParseSetFiles("file"))
+func SetMust(s *Set, err os.Error) *Set {
+ if err != nil {
+ panic(err)
+ }
+ return s
+}
+
+// ParseFiles parses the named files into a set of named templates.
+// Each file must be parseable by itself.
+// If an error occurs, parsing stops and the returned set is nil.
+func (s *Set) ParseFiles(filenames ...string) (*Set, os.Error) {
+ for _, filename := range filenames {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ _, err = s.Parse(string(b))
+ if err != nil {
+ return nil, err
+ }
+ }
+ return s, nil
+}
+
+// ParseSetFiles creates a new Set and parses the set definition from the
+// named files. Each file must be individually parseable.
+func ParseSetFiles(filenames ...string) (*Set, os.Error) {
+ s := new(Set)
+ for _, filename := range filenames {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ _, err = s.Parse(string(b))
+ if err != nil {
+ return nil, err
+ }
+ }
+ return s, nil
+}
+
+// ParseGlob parses the set definition from the files identified by the
+// pattern. The pattern is processed by filepath.Glob and must match at
+// least one file.
+// If an error occurs, parsing stops and the returned set is nil.
+func (s *Set) ParseGlob(pattern string) (*Set, os.Error) {
+ filenames, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ if len(filenames) == 0 {
+ return nil, fmt.Errorf("pattern matches no files: %#q", pattern)
+ }
+ return s.ParseFiles(filenames...)
+}
+
+// ParseSetGlob creates a new Set and parses the set definition from the
+// files identified by the pattern. The pattern is processed by filepath.Glob
+// and must match at least one file.
+func ParseSetGlob(pattern string) (*Set, os.Error) {
+ set, err := new(Set).ParseGlob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ return set, nil
+}
+
+// Functions and methods to parse stand-alone template files into a set.
+
+// ParseTemplateFiles parses the named template files and adds
+// them to the set. Each template will be named the base name of
+// its file.
+// Unlike with ParseFiles, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFiles is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself.
+// If an error occurs, parsing stops and the returned set is nil.
+func (s *Set) ParseTemplateFiles(filenames ...string) (*Set, os.Error) {
+ for _, filename := range filenames {
+ _, err := parseFileInSet(filename, s)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return s, nil
+}
+
+// ParseTemplateGlob parses the template files matched by the
+// patern and adds them to the set. Each template will be named
+// the base name of its file.
+// Unlike with ParseGlob, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateGlob is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself.
+// If an error occurs, parsing stops and the returned set is nil.
+func (s *Set) ParseTemplateGlob(pattern string) (*Set, os.Error) {
+ filenames, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ for _, filename := range filenames {
+ _, err := parseFileInSet(filename, s)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return s, nil
+}
+
+// ParseTemplateFiles creates a set by parsing the named files,
+// each of which defines a single template. Each template will be
+// named the base name of its file.
+// Unlike with ParseFiles, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateFiles is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func ParseTemplateFiles(filenames ...string) (*Set, os.Error) {
+ set := new(Set)
+ set.init()
+ for _, filename := range filenames {
+ t, err := ParseFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ if err := set.add(t); err != nil {
+ return nil, err
+ }
+ }
+ return set, nil
+}
+
+// ParseTemplateGlob creates a set by parsing the files matched
+// by the pattern, each of which defines a single template. Each
+// template will be named the base name of its file.
+// Unlike with ParseGlob, each file should be a stand-alone template
+// definition suitable for Template.Parse (not Set.Parse); that is, the
+// file does not contain {{define}} clauses. ParseTemplateGlob is
+// therefore equivalent to calling the ParseFile function to create
+// individual templates, which are then added to the set.
+// Each file must be parseable by itself. Parsing stops if an error is
+// encountered.
+func ParseTemplateGlob(pattern string) (*Set, os.Error) {
+ set := new(Set)
+ filenames, err := filepath.Glob(pattern)
+ if err != nil {
+ return nil, err
+ }
+ for _, filename := range filenames {
+ t, err := ParseFile(filename)
+ if err != nil {
+ return nil, err
+ }
+ if err := set.add(t); err != nil {
+ return nil, err
+ }
+ }
+ return set, nil
+}
diff --git a/libgo/go/template/parse.go b/libgo/go/template/parse.go
new file mode 100644
index 00000000000..b089c599a47
--- /dev/null
+++ b/libgo/go/template/parse.go
@@ -0,0 +1,85 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "os"
+ "reflect"
+ "template/parse"
+)
+
+// Template is the representation of a parsed template.
+type Template struct {
+ name string
+ *parse.Tree
+ // We use two maps, one for parsing and one for execution.
+ // This separation makes the API cleaner since it doesn't
+ // expose reflection to the client.
+ parseFuncs FuncMap
+ execFuncs map[string]reflect.Value
+ set *Set // can be nil.
+}
+
+// Name returns the name of the template.
+func (t *Template) Name() string {
+ return t.name
+}
+
+// Parsing.
+
+// New allocates a new template with the given name.
+func New(name string) *Template {
+ return &Template{
+ name: name,
+ parseFuncs: make(FuncMap),
+ execFuncs: make(map[string]reflect.Value),
+ }
+}
+
+// Funcs adds the elements of the argument map to the template's function
+// map. It panics if a value in the map is not a function with appropriate
+// return type.
+// The return value is the template, so calls can be chained.
+func (t *Template) Funcs(funcMap FuncMap) *Template {
+ addValueFuncs(t.execFuncs, funcMap)
+ addFuncs(t.parseFuncs, funcMap)
+ return t
+}
+
+// Parse parses the template definition string to construct an internal
+// representation of the template for execution.
+func (t *Template) Parse(s string) (tmpl *Template, err os.Error) {
+ t.Tree, err = parse.New(t.name).Parse(s, t.parseFuncs, builtins)
+ if err != nil {
+ return nil, err
+ }
+ return t, nil
+}
+
+// ParseInSet parses the template definition string to construct an internal
+// representation of the template for execution. It also adds the template
+// to the set.
+// Function bindings are checked against those in the set.
+func (t *Template) ParseInSet(s string, set *Set) (tmpl *Template, err os.Error) {
+ var setFuncs FuncMap
+ if set != nil {
+ setFuncs = set.parseFuncs
+ }
+ t.Tree, err = parse.New(t.name).Parse(s, t.parseFuncs, setFuncs, builtins)
+ if err != nil {
+ return nil, err
+ }
+ t.addToSet(set)
+ return t, nil
+}
+
+// addToSet adds the template to the set, verifying it's not being double-assigned.
+func (t *Template) addToSet(set *Set) {
+ if set == nil || t.set == set {
+ return
+ }
+ // If double-assigned, Add will panic and we will turn that into an error.
+ set.Add(t)
+}
diff --git a/libgo/go/template/parse/lex.go b/libgo/go/template/parse/lex.go
new file mode 100644
index 00000000000..83ad6c628bf
--- /dev/null
+++ b/libgo/go/template/parse/lex.go
@@ -0,0 +1,472 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parse
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// item represents a token or text string returned from the scanner.
+type item struct {
+ typ itemType
+ val string
+}
+
+func (i item) String() string {
+ switch {
+ case i.typ == itemEOF:
+ return "EOF"
+ case i.typ == itemError:
+ return i.val
+ case i.typ > itemKeyword:
+ return fmt.Sprintf("<%s>", i.val)
+ case len(i.val) > 10:
+ return fmt.Sprintf("%.10q...", i.val)
+ }
+ return fmt.Sprintf("%q", i.val)
+}
+
+// itemType identifies the type of lex items.
+type itemType int
+
+const (
+ itemError itemType = iota // error occurred; value is text of error
+ itemBool // boolean constant
+ itemChar // printable ASCII character; grab bag for comma etc.
+ itemCharConstant // character constant
+ itemComplex // complex constant (1+2i); imaginary is just a number
+ itemColonEquals // colon-equals (':=') introducing a declaration
+ itemEOF
+ itemField // alphanumeric identifier, starting with '.', possibly chained ('.x.y')
+ itemIdentifier // alphanumeric identifier
+ itemLeftDelim // left action delimiter
+ itemNumber // simple number, including imaginary
+ itemPipe // pipe symbol
+ itemRawString // raw quoted string (includes quotes)
+ itemRightDelim // right action delimiter
+ itemString // quoted string (includes quotes)
+ itemText // plain text
+ itemVariable // variable starting with '$', such as '$' or '$1' or '$hello'.
+ // Keywords appear after all the rest.
+ itemKeyword // used only to delimit the keywords
+ itemDot // the cursor, spelled '.'.
+ itemDefine // define keyword
+ itemElse // else keyword
+ itemEnd // end keyword
+ itemIf // if keyword
+ itemRange // range keyword
+ itemTemplate // template keyword
+ itemWith // with keyword
+)
+
+// Make the types prettyprint.
+var itemName = map[itemType]string{
+ itemError: "error",
+ itemBool: "bool",
+ itemChar: "char",
+ itemCharConstant: "charconst",
+ itemComplex: "complex",
+ itemColonEquals: ":=",
+ itemEOF: "EOF",
+ itemField: "field",
+ itemIdentifier: "identifier",
+ itemLeftDelim: "left delim",
+ itemNumber: "number",
+ itemPipe: "pipe",
+ itemRawString: "raw string",
+ itemRightDelim: "right delim",
+ itemString: "string",
+ itemVariable: "variable",
+ // keywords
+ itemDot: ".",
+ itemDefine: "define",
+ itemElse: "else",
+ itemIf: "if",
+ itemEnd: "end",
+ itemRange: "range",
+ itemTemplate: "template",
+ itemWith: "with",
+}
+
+func (i itemType) String() string {
+ s := itemName[i]
+ if s == "" {
+ return fmt.Sprintf("item%d", int(i))
+ }
+ return s
+}
+
+var key = map[string]itemType{
+ ".": itemDot,
+ "define": itemDefine,
+ "else": itemElse,
+ "end": itemEnd,
+ "if": itemIf,
+ "range": itemRange,
+ "template": itemTemplate,
+ "with": itemWith,
+}
+
+const eof = -1
+
+// stateFn represents the state of the scanner as a function that returns the next state.
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner.
+type lexer struct {
+ name string // the name of the input; used only for error reports.
+ input string // the string being scanned.
+ state stateFn // the next lexing function to enter
+ pos int // current position in the input.
+ start int // start position of this item.
+ width int // width of last rune read from input.
+ items chan item // channel of scanned items.
+}
+
+// next returns the next rune in the input.
+func (l *lexer) next() (rune int) {
+ if l.pos >= len(l.input) {
+ l.width = 0
+ return eof
+ }
+ rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
+ l.pos += l.width
+ return rune
+}
+
+// peek returns but does not consume the next rune in the input.
+func (l *lexer) peek() int {
+ rune := l.next()
+ l.backup()
+ return rune
+}
+
+// backup steps back one rune. Can only be called once per call of next.
+func (l *lexer) backup() {
+ l.pos -= l.width
+}
+
+// emit passes an item back to the client.
+func (l *lexer) emit(t itemType) {
+ l.items <- item{t, l.input[l.start:l.pos]}
+ l.start = l.pos
+}
+
+// ignore skips over the pending input before this point.
+func (l *lexer) ignore() {
+ l.start = l.pos
+}
+
+// accept consumes the next rune if it's from the valid set.
+func (l *lexer) accept(valid string) bool {
+ if strings.IndexRune(valid, l.next()) >= 0 {
+ return true
+ }
+ l.backup()
+ return false
+}
+
+// acceptRun consumes a run of runes from the valid set.
+func (l *lexer) acceptRun(valid string) {
+ for strings.IndexRune(valid, l.next()) >= 0 {
+ }
+ l.backup()
+}
+
+// lineNumber reports which line we're on. Doing it this way
+// means we don't have to worry about peek double counting.
+func (l *lexer) lineNumber() int {
+ return 1 + strings.Count(l.input[:l.pos], "\n")
+}
+
+// error returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.run.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+ l.items <- item{itemError, fmt.Sprintf(format, args...)}
+ return nil
+}
+
+// nextItem returns the next item from the input.
+func (l *lexer) nextItem() item {
+ for {
+ select {
+ case item := <-l.items:
+ return item
+ default:
+ l.state = l.state(l)
+ }
+ }
+ panic("not reached")
+}
+
+// lex creates a new scanner for the input string.
+func lex(name, input string) *lexer {
+ l := &lexer{
+ name: name,
+ input: input,
+ state: lexText,
+ items: make(chan item, 2), // Two items of buffering is sufficient for all state functions
+ }
+ return l
+}
+
+// state functions
+
+const (
+ leftDelim = "{{"
+ rightDelim = "}}"
+ leftComment = "{{/*"
+ rightComment = "*/}}"
+)
+
+// lexText scans until an opening action delimiter, "{{".
+func lexText(l *lexer) stateFn {
+ for {
+ if strings.HasPrefix(l.input[l.pos:], leftDelim) {
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ return lexLeftDelim
+ }
+ if l.next() == eof {
+ break
+ }
+ }
+ // Correctly reached EOF.
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.emit(itemEOF)
+ return nil
+}
+
+// lexLeftDelim scans the left delimiter, which is known to be present.
+func lexLeftDelim(l *lexer) stateFn {
+ if strings.HasPrefix(l.input[l.pos:], leftComment) {
+ return lexComment
+ }
+ l.pos += len(leftDelim)
+ l.emit(itemLeftDelim)
+ return lexInsideAction
+}
+
+// lexComment scans a comment. The left comment marker is known to be present.
+func lexComment(l *lexer) stateFn {
+ i := strings.Index(l.input[l.pos:], rightComment)
+ if i < 0 {
+ return l.errorf("unclosed comment")
+ }
+ l.pos += i + len(rightComment)
+ l.ignore()
+ return lexText
+}
+
+// lexRightDelim scans the right delimiter, which is known to be present.
+func lexRightDelim(l *lexer) stateFn {
+ l.pos += len(rightDelim)
+ l.emit(itemRightDelim)
+ return lexText
+}
+
+// lexInsideAction scans the elements inside action delimiters.
+func lexInsideAction(l *lexer) stateFn {
+ // Either number, quoted string, or identifier.
+ // Spaces separate and are ignored.
+ // Pipe symbols separate and are emitted.
+ if strings.HasPrefix(l.input[l.pos:], rightDelim) {
+ return lexRightDelim
+ }
+ switch r := l.next(); {
+ case r == eof || r == '\n':
+ return l.errorf("unclosed action")
+ case isSpace(r):
+ l.ignore()
+ case r == ':':
+ if l.next() != '=' {
+ return l.errorf("expected :=")
+ }
+ l.emit(itemColonEquals)
+ case r == '|':
+ l.emit(itemPipe)
+ case r == '"':
+ return lexQuote
+ case r == '`':
+ return lexRawQuote
+ case r == '$':
+ return lexIdentifier
+ case r == '\'':
+ return lexChar
+ case r == '.':
+ // special look-ahead for ".field" so we don't break l.backup().
+ if l.pos < len(l.input) {
+ r := l.input[l.pos]
+ if r < '0' || '9' < r {
+ return lexIdentifier // itemDot comes from the keyword table.
+ }
+ }
+ fallthrough // '.' can start a number.
+ case r == '+' || r == '-' || ('0' <= r && r <= '9'):
+ l.backup()
+ return lexNumber
+ case isAlphaNumeric(r):
+ l.backup()
+ return lexIdentifier
+ case r <= unicode.MaxASCII && unicode.IsPrint(r):
+ l.emit(itemChar)
+ return lexInsideAction
+ default:
+ return l.errorf("unrecognized character in action: %#U", r)
+ }
+ return lexInsideAction
+}
+
+// lexIdentifier scans an alphanumeric or field.
+func lexIdentifier(l *lexer) stateFn {
+Loop:
+ for {
+ switch r := l.next(); {
+ case isAlphaNumeric(r):
+ // absorb.
+ case r == '.' && (l.input[l.start] == '.' || l.input[l.start] == '$'):
+ // field chaining; absorb into one token.
+ default:
+ l.backup()
+ word := l.input[l.start:l.pos]
+ switch {
+ case key[word] > itemKeyword:
+ l.emit(key[word])
+ case word[0] == '.':
+ l.emit(itemField)
+ case word[0] == '$':
+ l.emit(itemVariable)
+ case word == "true", word == "false":
+ l.emit(itemBool)
+ default:
+ l.emit(itemIdentifier)
+ }
+ break Loop
+ }
+ }
+ return lexInsideAction
+}
+
+// lexChar scans a character constant. The initial quote is already
+// scanned. Syntax checking is done by the parse.
+func lexChar(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case '\\':
+ if r := l.next(); r != eof && r != '\n' {
+ break
+ }
+ fallthrough
+ case eof, '\n':
+ return l.errorf("unterminated character constant")
+ case '\'':
+ break Loop
+ }
+ }
+ l.emit(itemCharConstant)
+ return lexInsideAction
+}
+
+// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
+// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
+// and "089" - but when it's wrong the input is invalid and the parser (via
+// strconv) will notice.
+func lexNumber(l *lexer) stateFn {
+ if !l.scanNumber() {
+ return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+ }
+ if sign := l.peek(); sign == '+' || sign == '-' {
+ // Complex: 1+2i. No spaces, must end in 'i'.
+ if !l.scanNumber() || l.input[l.pos-1] != 'i' {
+ return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+ }
+ l.emit(itemComplex)
+ } else {
+ l.emit(itemNumber)
+ }
+ return lexInsideAction
+}
+
+func (l *lexer) scanNumber() bool {
+ // Optional leading sign.
+ l.accept("+-")
+ // Is it hex?
+ digits := "0123456789"
+ if l.accept("0") && l.accept("xX") {
+ digits = "0123456789abcdefABCDEF"
+ }
+ l.acceptRun(digits)
+ if l.accept(".") {
+ l.acceptRun(digits)
+ }
+ if l.accept("eE") {
+ l.accept("+-")
+ l.acceptRun("0123456789")
+ }
+ // Is it imaginary?
+ l.accept("i")
+ // Next thing mustn't be alphanumeric.
+ if isAlphaNumeric(l.peek()) {
+ l.next()
+ return false
+ }
+ return true
+}
+
+// lexQuote scans a quoted string.
+func lexQuote(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case '\\':
+ if r := l.next(); r != eof && r != '\n' {
+ break
+ }
+ fallthrough
+ case eof, '\n':
+ return l.errorf("unterminated quoted string")
+ case '"':
+ break Loop
+ }
+ }
+ l.emit(itemString)
+ return lexInsideAction
+}
+
+// lexRawQuote scans a raw quoted string.
+func lexRawQuote(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case eof, '\n':
+ return l.errorf("unterminated raw quoted string")
+ case '`':
+ break Loop
+ }
+ }
+ l.emit(itemRawString)
+ return lexInsideAction
+}
+
+// isSpace reports whether r is a space character.
+func isSpace(r int) bool {
+ switch r {
+ case ' ', '\t', '\n', '\r':
+ return true
+ }
+ return false
+}
+
+// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
+func isAlphaNumeric(r int) bool {
+ return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
+}
diff --git a/libgo/go/template/parse/lex_test.go b/libgo/go/template/parse/lex_test.go
new file mode 100644
index 00000000000..d71c8e66df2
--- /dev/null
+++ b/libgo/go/template/parse/lex_test.go
@@ -0,0 +1,223 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parse
+
+import (
+ "reflect"
+ "testing"
+)
+
+type lexTest struct {
+ name string
+ input string
+ items []item
+}
+
+var (
+ tEOF = item{itemEOF, ""}
+ tLeft = item{itemLeftDelim, "{{"}
+ tRight = item{itemRightDelim, "}}"}
+ tRange = item{itemRange, "range"}
+ tPipe = item{itemPipe, "|"}
+ tFor = item{itemIdentifier, "for"}
+ tQuote = item{itemString, `"abc \n\t\" "`}
+ raw = "`" + `abc\n\t\" ` + "`"
+ tRawQuote = item{itemRawString, raw}
+)
+
+var lexTests = []lexTest{
+ {"empty", "", []item{tEOF}},
+ {"spaces", " \t\n", []item{{itemText, " \t\n"}, tEOF}},
+ {"text", `now is the time`, []item{{itemText, "now is the time"}, tEOF}},
+ {"text with comment", "hello-{{/* this is a comment */}}-world", []item{
+ {itemText, "hello-"},
+ {itemText, "-world"},
+ tEOF,
+ }},
+ {"punctuation", "{{,@%}}", []item{
+ tLeft,
+ {itemChar, ","},
+ {itemChar, "@"},
+ {itemChar, "%"},
+ tRight,
+ tEOF,
+ }},
+ {"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
+ {"for", `{{for }}`, []item{tLeft, tFor, tRight, tEOF}},
+ {"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
+ {"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
+ {"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
+ tLeft,
+ {itemNumber, "1"},
+ {itemNumber, "02"},
+ {itemNumber, "0x14"},
+ {itemNumber, "-7.2i"},
+ {itemNumber, "1e3"},
+ {itemNumber, "+1.2e-4"},
+ {itemNumber, "4.2i"},
+ {itemComplex, "1+2i"},
+ tRight,
+ tEOF,
+ }},
+ {"characters", `{{'a' '\n' '\'' '\\' '\u00FF' '\xFF' '本'}}`, []item{
+ tLeft,
+ {itemCharConstant, `'a'`},
+ {itemCharConstant, `'\n'`},
+ {itemCharConstant, `'\''`},
+ {itemCharConstant, `'\\'`},
+ {itemCharConstant, `'\u00FF'`},
+ {itemCharConstant, `'\xFF'`},
+ {itemCharConstant, `'本'`},
+ tRight,
+ tEOF,
+ }},
+ {"bools", "{{true false}}", []item{
+ tLeft,
+ {itemBool, "true"},
+ {itemBool, "false"},
+ tRight,
+ tEOF,
+ }},
+ {"dot", "{{.}}", []item{
+ tLeft,
+ {itemDot, "."},
+ tRight,
+ tEOF,
+ }},
+ {"dots", "{{.x . .2 .x.y}}", []item{
+ tLeft,
+ {itemField, ".x"},
+ {itemDot, "."},
+ {itemNumber, ".2"},
+ {itemField, ".x.y"},
+ tRight,
+ tEOF,
+ }},
+ {"keywords", "{{range if else end with}}", []item{
+ tLeft,
+ {itemRange, "range"},
+ {itemIf, "if"},
+ {itemElse, "else"},
+ {itemEnd, "end"},
+ {itemWith, "with"},
+ tRight,
+ tEOF,
+ }},
+ {"variables", "{{$c := printf $ $hello $23 $ $var.Field .Method}}", []item{
+ tLeft,
+ {itemVariable, "$c"},
+ {itemColonEquals, ":="},
+ {itemIdentifier, "printf"},
+ {itemVariable, "$"},
+ {itemVariable, "$hello"},
+ {itemVariable, "$23"},
+ {itemVariable, "$"},
+ {itemVariable, "$var.Field"},
+ {itemField, ".Method"},
+ tRight,
+ tEOF,
+ }},
+ {"pipeline", `intro {{echo hi 1.2 |noargs|args 1 "hi"}} outro`, []item{
+ {itemText, "intro "},
+ tLeft,
+ {itemIdentifier, "echo"},
+ {itemIdentifier, "hi"},
+ {itemNumber, "1.2"},
+ tPipe,
+ {itemIdentifier, "noargs"},
+ tPipe,
+ {itemIdentifier, "args"},
+ {itemNumber, "1"},
+ {itemString, `"hi"`},
+ tRight,
+ {itemText, " outro"},
+ tEOF,
+ }},
+ {"declaration", "{{$v := 3}}", []item{
+ tLeft,
+ {itemVariable, "$v"},
+ {itemColonEquals, ":="},
+ {itemNumber, "3"},
+ tRight,
+ tEOF,
+ }},
+ {"2 declarations", "{{$v , $w := 3}}", []item{
+ tLeft,
+ {itemVariable, "$v"},
+ {itemChar, ","},
+ {itemVariable, "$w"},
+ {itemColonEquals, ":="},
+ {itemNumber, "3"},
+ tRight,
+ tEOF,
+ }},
+ // errors
+ {"badchar", "#{{\x01}}", []item{
+ {itemText, "#"},
+ tLeft,
+ {itemError, "unrecognized character in action: U+0001"},
+ }},
+ {"unclosed action", "{{\n}}", []item{
+ tLeft,
+ {itemError, "unclosed action"},
+ }},
+ {"EOF in action", "{{range", []item{
+ tLeft,
+ tRange,
+ {itemError, "unclosed action"},
+ }},
+ {"unclosed quote", "{{\"\n\"}}", []item{
+ tLeft,
+ {itemError, "unterminated quoted string"},
+ }},
+ {"unclosed raw quote", "{{`xx\n`}}", []item{
+ tLeft,
+ {itemError, "unterminated raw quoted string"},
+ }},
+ {"unclosed char constant", "{{'\n}}", []item{
+ tLeft,
+ {itemError, "unterminated character constant"},
+ }},
+ {"bad number", "{{3k}}", []item{
+ tLeft,
+ {itemError, `bad number syntax: "3k"`},
+ }},
+
+ // Fixed bugs
+ // Many elements in an action blew the lookahead until
+ // we made lexInsideAction not loop.
+ {"long pipeline deadlock", "{{|||||}}", []item{
+ tLeft,
+ tPipe,
+ tPipe,
+ tPipe,
+ tPipe,
+ tPipe,
+ tRight,
+ tEOF,
+ }},
+}
+
+// collect gathers the emitted items into a slice.
+func collect(t *lexTest) (items []item) {
+ l := lex(t.name, t.input)
+ for {
+ item := l.nextItem()
+ items = append(items, item)
+ if item.typ == itemEOF || item.typ == itemError {
+ break
+ }
+ }
+ return
+}
+
+func TestLex(t *testing.T) {
+ for _, test := range lexTests {
+ items := collect(&test)
+ if !reflect.DeepEqual(items, test.items) {
+ t.Errorf("%s: got\n\t%v\nexpected\n\t%v", test.name, items, test.items)
+ }
+ }
+}
diff --git a/libgo/go/template/parse/node.go b/libgo/go/template/parse/node.go
new file mode 100644
index 00000000000..6f0b429b958
--- /dev/null
+++ b/libgo/go/template/parse/node.go
@@ -0,0 +1,470 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse nodes.
+
+package parse
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// A node is an element in the parse tree. The interface is trivial.
+type Node interface {
+ Type() NodeType
+ String() string
+}
+
+// NodeType identifies the type of a parse tree node.
+type NodeType int
+
+// Type returns itself and provides an easy default implementation
+// for embedding in a Node. Embedded in all non-trivial Nodes.
+func (t NodeType) Type() NodeType {
+ return t
+}
+
+const (
+ NodeText NodeType = iota // Plain text.
+ NodeAction // A simple action such as field evaluation.
+ NodeBool // A boolean constant.
+ NodeCommand // An element of a pipeline.
+ NodeDot // The cursor, dot.
+ nodeElse // An else action. Not added to tree.
+ nodeEnd // An end action. Not added to tree.
+ NodeField // A field or method name.
+ NodeIdentifier // An identifier; always a function name.
+ NodeIf // An if action.
+ NodeList // A list of Nodes.
+ NodeNumber // A numerical constant.
+ NodePipe // A pipeline of commands.
+ NodeRange // A range action.
+ NodeString // A string constant.
+ NodeTemplate // A template invocation action.
+ NodeVariable // A $ variable.
+ NodeWith // A with action.
+)
+
+// Nodes.
+
+// ListNode holds a sequence of nodes.
+type ListNode struct {
+ NodeType
+ Nodes []Node // The element nodes in lexical order.
+}
+
+func newList() *ListNode {
+ return &ListNode{NodeType: NodeList}
+}
+
+func (l *ListNode) append(n Node) {
+ l.Nodes = append(l.Nodes, n)
+}
+
+func (l *ListNode) String() string {
+ b := new(bytes.Buffer)
+ fmt.Fprint(b, "[")
+ for _, n := range l.Nodes {
+ fmt.Fprint(b, n)
+ }
+ fmt.Fprint(b, "]")
+ return b.String()
+}
+
+// TextNode holds plain text.
+type TextNode struct {
+ NodeType
+ Text []byte // The text; may span newlines.
+}
+
+func newText(text string) *TextNode {
+ return &TextNode{NodeType: NodeText, Text: []byte(text)}
+}
+
+func (t *TextNode) String() string {
+ return fmt.Sprintf("(text: %q)", t.Text)
+}
+
+// PipeNode holds a pipeline with optional declaration
+type PipeNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Decl []*VariableNode // Variable declarations in lexical order.
+ Cmds []*CommandNode // The commands in lexical order.
+}
+
+func newPipeline(line int, decl []*VariableNode) *PipeNode {
+ return &PipeNode{NodeType: NodePipe, Line: line, Decl: decl}
+}
+
+func (p *PipeNode) append(command *CommandNode) {
+ p.Cmds = append(p.Cmds, command)
+}
+
+func (p *PipeNode) String() string {
+ if p.Decl != nil {
+ return fmt.Sprintf("%v := %v", p.Decl, p.Cmds)
+ }
+ return fmt.Sprintf("%v", p.Cmds)
+}
+
+// ActionNode holds an action (something bounded by delimiters).
+// Control actions have their own nodes; ActionNode represents simple
+// ones such as field evaluations.
+type ActionNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Pipe *PipeNode // The pipeline in the action.
+}
+
+func newAction(line int, pipe *PipeNode) *ActionNode {
+ return &ActionNode{NodeType: NodeAction, Line: line, Pipe: pipe}
+}
+
+func (a *ActionNode) String() string {
+ return fmt.Sprintf("(action: %v)", a.Pipe)
+}
+
+// CommandNode holds a command (a pipeline inside an evaluating action).
+type CommandNode struct {
+ NodeType
+ Args []Node // Arguments in lexical order: Identifier, field, or constant.
+}
+
+func newCommand() *CommandNode {
+ return &CommandNode{NodeType: NodeCommand}
+}
+
+func (c *CommandNode) append(arg Node) {
+ c.Args = append(c.Args, arg)
+}
+
+func (c *CommandNode) String() string {
+ return fmt.Sprintf("(command: %v)", c.Args)
+}
+
+// IdentifierNode holds an identifier.
+type IdentifierNode struct {
+ NodeType
+ Ident string // The identifier's name.
+}
+
+// NewIdentifier returns a new IdentifierNode with the given identifier name.
+func NewIdentifier(ident string) *IdentifierNode {
+ return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident}
+}
+
+func (i *IdentifierNode) String() string {
+ return fmt.Sprintf("I=%s", i.Ident)
+}
+
+// VariableNode holds a list of variable names. The dollar sign is
+// part of the name.
+type VariableNode struct {
+ NodeType
+ Ident []string // Variable names in lexical order.
+}
+
+func newVariable(ident string) *VariableNode {
+ return &VariableNode{NodeType: NodeVariable, Ident: strings.Split(ident, ".")}
+}
+
+func (v *VariableNode) String() string {
+ return fmt.Sprintf("V=%s", v.Ident)
+}
+
+// DotNode holds the special identifier '.'. It is represented by a nil pointer.
+type DotNode bool
+
+func newDot() *DotNode {
+ return nil
+}
+
+func (d *DotNode) Type() NodeType {
+ return NodeDot
+}
+
+func (d *DotNode) String() string {
+ return "{{<.>}}"
+}
+
+// FieldNode holds a field (identifier starting with '.').
+// The names may be chained ('.x.y').
+// The period is dropped from each ident.
+type FieldNode struct {
+ NodeType
+ Ident []string // The identifiers in lexical order.
+}
+
+func newField(ident string) *FieldNode {
+ return &FieldNode{NodeType: NodeField, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period
+}
+
+func (f *FieldNode) String() string {
+ return fmt.Sprintf("F=%s", f.Ident)
+}
+
+// BoolNode holds a boolean constant.
+type BoolNode struct {
+ NodeType
+ True bool // The value of the boolean constant.
+}
+
+func newBool(true bool) *BoolNode {
+ return &BoolNode{NodeType: NodeBool, True: true}
+}
+
+func (b *BoolNode) String() string {
+ return fmt.Sprintf("B=%t", b.True)
+}
+
+// NumberNode holds a number: signed or unsigned integer, float, or complex.
+// The value is parsed and stored under all the types that can represent the value.
+// This simulates in a small amount of code the behavior of Go's ideal constants.
+type NumberNode struct {
+ NodeType
+ IsInt bool // Number has an integral value.
+ IsUint bool // Number has an unsigned integral value.
+ IsFloat bool // Number has a floating-point value.
+ IsComplex bool // Number is complex.
+ Int64 int64 // The signed integer value.
+ Uint64 uint64 // The unsigned integer value.
+ Float64 float64 // The floating-point value.
+ Complex128 complex128 // The complex value.
+ Text string // The original textual representation from the input.
+}
+
+func newNumber(text string, typ itemType) (*NumberNode, os.Error) {
+ n := &NumberNode{NodeType: NodeNumber, Text: text}
+ switch typ {
+ case itemCharConstant:
+ rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0])
+ if err != nil {
+ return nil, err
+ }
+ if tail != "'" {
+ return nil, fmt.Errorf("malformed character constant: %s", text)
+ }
+ n.Int64 = int64(rune)
+ n.IsInt = true
+ n.Uint64 = uint64(rune)
+ n.IsUint = true
+ n.Float64 = float64(rune) // odd but those are the rules.
+ n.IsFloat = true
+ return n, nil
+ case itemComplex:
+ // fmt.Sscan can parse the pair, so let it do the work.
+ if _, err := fmt.Sscan(text, &n.Complex128); err != nil {
+ return nil, err
+ }
+ n.IsComplex = true
+ n.simplifyComplex()
+ return n, nil
+ }
+ // Imaginary constants can only be complex unless they are zero.
+ if len(text) > 0 && text[len(text)-1] == 'i' {
+ f, err := strconv.Atof64(text[:len(text)-1])
+ if err == nil {
+ n.IsComplex = true
+ n.Complex128 = complex(0, f)
+ n.simplifyComplex()
+ return n, nil
+ }
+ }
+ // Do integer test first so we get 0x123 etc.
+ u, err := strconv.Btoui64(text, 0) // will fail for -0; fixed below.
+ if err == nil {
+ n.IsUint = true
+ n.Uint64 = u
+ }
+ i, err := strconv.Btoi64(text, 0)
+ if err == nil {
+ n.IsInt = true
+ n.Int64 = i
+ if i == 0 {
+ n.IsUint = true // in case of -0.
+ n.Uint64 = u
+ }
+ }
+ // If an integer extraction succeeded, promote the float.
+ if n.IsInt {
+ n.IsFloat = true
+ n.Float64 = float64(n.Int64)
+ } else if n.IsUint {
+ n.IsFloat = true
+ n.Float64 = float64(n.Uint64)
+ } else {
+ f, err := strconv.Atof64(text)
+ if err == nil {
+ n.IsFloat = true
+ n.Float64 = f
+ // If a floating-point extraction succeeded, extract the int if needed.
+ if !n.IsInt && float64(int64(f)) == f {
+ n.IsInt = true
+ n.Int64 = int64(f)
+ }
+ if !n.IsUint && float64(uint64(f)) == f {
+ n.IsUint = true
+ n.Uint64 = uint64(f)
+ }
+ }
+ }
+ if !n.IsInt && !n.IsUint && !n.IsFloat {
+ return nil, fmt.Errorf("illegal number syntax: %q", text)
+ }
+ return n, nil
+}
+
+// simplifyComplex pulls out any other types that are represented by the complex number.
+// These all require that the imaginary part be zero.
+func (n *NumberNode) simplifyComplex() {
+ n.IsFloat = imag(n.Complex128) == 0
+ if n.IsFloat {
+ n.Float64 = real(n.Complex128)
+ n.IsInt = float64(int64(n.Float64)) == n.Float64
+ if n.IsInt {
+ n.Int64 = int64(n.Float64)
+ }
+ n.IsUint = float64(uint64(n.Float64)) == n.Float64
+ if n.IsUint {
+ n.Uint64 = uint64(n.Float64)
+ }
+ }
+}
+
+func (n *NumberNode) String() string {
+ return fmt.Sprintf("N=%s", n.Text)
+}
+
+// StringNode holds a string constant. The value has been "unquoted".
+type StringNode struct {
+ NodeType
+ Quoted string // The original text of the string, with quotes.
+ Text string // The string, after quote processing.
+}
+
+func newString(orig, text string) *StringNode {
+ return &StringNode{NodeType: NodeString, Quoted: orig, Text: text}
+}
+
+func (s *StringNode) String() string {
+ return fmt.Sprintf("S=%#q", s.Text)
+}
+
+// endNode represents an {{end}} action. It is represented by a nil pointer.
+// It does not appear in the final parse tree.
+type endNode bool
+
+func newEnd() *endNode {
+ return nil
+}
+
+func (e *endNode) Type() NodeType {
+ return nodeEnd
+}
+
+func (e *endNode) String() string {
+ return "{{end}}"
+}
+
+// elseNode represents an {{else}} action. Does not appear in the final tree.
+type elseNode struct {
+ NodeType
+ Line int // The line number in the input.
+}
+
+func newElse(line int) *elseNode {
+ return &elseNode{NodeType: nodeElse, Line: line}
+}
+
+func (e *elseNode) Type() NodeType {
+ return nodeElse
+}
+
+func (e *elseNode) String() string {
+ return "{{else}}"
+}
+
+// IfNode represents an {{if}} action and its commands.
+type IfNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Pipe *PipeNode // The pipeline to be evaluated.
+ List *ListNode // What to execute if the value is non-empty.
+ ElseList *ListNode // What to execute if the value is empty (nil if absent).
+}
+
+func newIf(line int, pipe *PipeNode, list, elseList *ListNode) *IfNode {
+ return &IfNode{NodeType: NodeIf, Line: line, Pipe: pipe, List: list, ElseList: elseList}
+}
+
+func (i *IfNode) String() string {
+ if i.ElseList != nil {
+ return fmt.Sprintf("({{if %s}} %s {{else}} %s)", i.Pipe, i.List, i.ElseList)
+ }
+ return fmt.Sprintf("({{if %s}} %s)", i.Pipe, i.List)
+}
+
+// RangeNode represents a {{range}} action and its commands.
+type RangeNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Pipe *PipeNode // The pipeline to be evaluated.
+ List *ListNode // What to execute if the value is non-empty.
+ ElseList *ListNode // What to execute if the value is empty (nil if absent).
+}
+
+func newRange(line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode {
+ return &RangeNode{NodeType: NodeRange, Line: line, Pipe: pipe, List: list, ElseList: elseList}
+}
+
+func (r *RangeNode) String() string {
+ if r.ElseList != nil {
+ return fmt.Sprintf("({{range %s}} %s {{else}} %s)", r.Pipe, r.List, r.ElseList)
+ }
+ return fmt.Sprintf("({{range %s}} %s)", r.Pipe, r.List)
+}
+
+// TemplateNode represents a {{template}} action.
+type TemplateNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Name string // The name of the template (unquoted).
+ Pipe *PipeNode // The command to evaluate as dot for the template.
+}
+
+func newTemplate(line int, name string, pipe *PipeNode) *TemplateNode {
+ return &TemplateNode{NodeType: NodeTemplate, Line: line, Name: name, Pipe: pipe}
+}
+
+func (t *TemplateNode) String() string {
+ if t.Pipe == nil {
+ return fmt.Sprintf("{{template %q}}", t.Name)
+ }
+ return fmt.Sprintf("{{template %q %s}}", t.Name, t.Pipe)
+}
+
+// WithNode represents a {{with}} action and its commands.
+type WithNode struct {
+ NodeType
+ Line int // The line number in the input.
+ Pipe *PipeNode // The pipeline to be evaluated.
+ List *ListNode // What to execute if the value is non-empty.
+ ElseList *ListNode // What to execute if the value is empty (nil if absent).
+}
+
+func newWith(line int, pipe *PipeNode, list, elseList *ListNode) *WithNode {
+ return &WithNode{NodeType: NodeWith, Line: line, Pipe: pipe, List: list, ElseList: elseList}
+}
+
+func (w *WithNode) String() string {
+ if w.ElseList != nil {
+ return fmt.Sprintf("({{with %s}} %s {{else}} %s)", w.Pipe, w.List, w.ElseList)
+ }
+ return fmt.Sprintf("({{with %s}} %s)", w.Pipe, w.List)
+}
diff --git a/libgo/go/template/parse/parse.go b/libgo/go/template/parse/parse.go
new file mode 100644
index 00000000000..6918074664e
--- /dev/null
+++ b/libgo/go/template/parse/parse.go
@@ -0,0 +1,436 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package parse builds parse trees for templates. The grammar is defined
+// in the documents for the template package.
+package parse
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "strconv"
+ "unicode"
+)
+
+// Tree is the representation of a parsed template.
+type Tree struct {
+ Name string // Name is the name of the template.
+ Root *ListNode // Root is the top-level root of the parse tree.
+ // Parsing only; cleared after parse.
+ funcs []map[string]interface{}
+ lex *lexer
+ token [2]item // two-token lookahead for parser.
+ peekCount int
+ vars []string // variables defined at the moment.
+}
+
+// next returns the next token.
+func (t *Tree) next() item {
+ if t.peekCount > 0 {
+ t.peekCount--
+ } else {
+ t.token[0] = t.lex.nextItem()
+ }
+ return t.token[t.peekCount]
+}
+
+// backup backs the input stream up one token.
+func (t *Tree) backup() {
+ t.peekCount++
+}
+
+// backup2 backs the input stream up two tokens
+func (t *Tree) backup2(t1 item) {
+ t.token[1] = t1
+ t.peekCount = 2
+}
+
+// peek returns but does not consume the next token.
+func (t *Tree) peek() item {
+ if t.peekCount > 0 {
+ return t.token[t.peekCount-1]
+ }
+ t.peekCount = 1
+ t.token[0] = t.lex.nextItem()
+ return t.token[0]
+}
+
+// Parsing.
+
+// New allocates a new template with the given name.
+func New(name string, funcs ...map[string]interface{}) *Tree {
+ return &Tree{
+ Name: name,
+ funcs: funcs,
+ }
+}
+
+// errorf formats the error and terminates processing.
+func (t *Tree) errorf(format string, args ...interface{}) {
+ t.Root = nil
+ format = fmt.Sprintf("template: %s:%d: %s", t.Name, t.lex.lineNumber(), format)
+ panic(fmt.Errorf(format, args...))
+}
+
+// error terminates processing.
+func (t *Tree) error(err os.Error) {
+ t.errorf("%s", err)
+}
+
+// expect consumes the next token and guarantees it has the required type.
+func (t *Tree) expect(expected itemType, context string) item {
+ token := t.next()
+ if token.typ != expected {
+ t.errorf("expected %s in %s; got %s", expected, context, token)
+ }
+ return token
+}
+
+// unexpected complains about the token and terminates processing.
+func (t *Tree) unexpected(token item, context string) {
+ t.errorf("unexpected %s in %s", token, context)
+}
+
+// recover is the handler that turns panics into returns from the top level of Parse.
+func (t *Tree) recover(errp *os.Error) {
+ e := recover()
+ if e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ if t != nil {
+ t.stopParse()
+ }
+ *errp = e.(os.Error)
+ }
+ return
+}
+
+// startParse starts the template parsing from the lexer.
+func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
+ t.Root = nil
+ t.lex = lex
+ t.vars = []string{"$"}
+ t.funcs = funcs
+}
+
+// stopParse terminates parsing.
+func (t *Tree) stopParse() {
+ t.lex = nil
+ t.vars = nil
+ t.funcs = nil
+}
+
+// atEOF returns true if, possibly after spaces, we're at EOF.
+func (t *Tree) atEOF() bool {
+ for {
+ token := t.peek()
+ switch token.typ {
+ case itemEOF:
+ return true
+ case itemText:
+ for _, r := range token.val {
+ if !unicode.IsSpace(r) {
+ return false
+ }
+ }
+ t.next() // skip spaces.
+ continue
+ }
+ break
+ }
+ return false
+}
+
+// Parse parses the template definition string to construct an internal
+// representation of the template for execution.
+func (t *Tree) Parse(s string, funcs ...map[string]interface{}) (tree *Tree, err os.Error) {
+ defer t.recover(&err)
+ t.startParse(funcs, lex(t.Name, s))
+ t.parse(true)
+ t.stopParse()
+ return t, nil
+}
+
+// parse is the helper for Parse.
+// It triggers an error if we expect EOF but don't reach it.
+func (t *Tree) parse(toEOF bool) (next Node) {
+ t.Root, next = t.itemList(true)
+ if toEOF && next != nil {
+ t.errorf("unexpected %s", next)
+ }
+ return next
+}
+
+// itemList:
+// textOrAction*
+// Terminates at EOF and at {{end}} or {{else}}, which is returned separately.
+// The toEOF flag tells whether we expect to reach EOF.
+func (t *Tree) itemList(toEOF bool) (list *ListNode, next Node) {
+ list = newList()
+ for t.peek().typ != itemEOF {
+ n := t.textOrAction()
+ switch n.Type() {
+ case nodeEnd, nodeElse:
+ return list, n
+ }
+ list.append(n)
+ }
+ if !toEOF {
+ t.unexpected(t.next(), "input")
+ }
+ return list, nil
+}
+
+// textOrAction:
+// text | action
+func (t *Tree) textOrAction() Node {
+ switch token := t.next(); token.typ {
+ case itemText:
+ return newText(token.val)
+ case itemLeftDelim:
+ return t.action()
+ default:
+ t.unexpected(token, "input")
+ }
+ return nil
+}
+
+// Action:
+// control
+// command ("|" command)*
+// Left delim is past. Now get actions.
+// First word could be a keyword such as range.
+func (t *Tree) action() (n Node) {
+ switch token := t.next(); token.typ {
+ case itemElse:
+ return t.elseControl()
+ case itemEnd:
+ return t.endControl()
+ case itemIf:
+ return t.ifControl()
+ case itemRange:
+ return t.rangeControl()
+ case itemTemplate:
+ return t.templateControl()
+ case itemWith:
+ return t.withControl()
+ }
+ t.backup()
+ // Do not pop variables; they persist until "end".
+ return newAction(t.lex.lineNumber(), t.pipeline("command"))
+}
+
+// Pipeline:
+// field or command
+// pipeline "|" pipeline
+func (t *Tree) pipeline(context string) (pipe *PipeNode) {
+ var decl []*VariableNode
+ // Are there declarations?
+ for {
+ if v := t.peek(); v.typ == itemVariable {
+ t.next()
+ if next := t.peek(); next.typ == itemColonEquals || next.typ == itemChar {
+ t.next()
+ variable := newVariable(v.val)
+ if len(variable.Ident) != 1 {
+ t.errorf("illegal variable in declaration: %s", v.val)
+ }
+ decl = append(decl, variable)
+ t.vars = append(t.vars, v.val)
+ if next.typ == itemChar && next.val == "," {
+ if context == "range" && len(decl) < 2 {
+ continue
+ }
+ t.errorf("too many declarations in %s", context)
+ }
+ } else {
+ t.backup2(v)
+ }
+ }
+ break
+ }
+ pipe = newPipeline(t.lex.lineNumber(), decl)
+ for {
+ switch token := t.next(); token.typ {
+ case itemRightDelim:
+ if len(pipe.Cmds) == 0 {
+ t.errorf("missing value for %s", context)
+ }
+ return
+ case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier,
+ itemVariable, itemNumber, itemRawString, itemString:
+ t.backup()
+ pipe.append(t.command())
+ default:
+ t.unexpected(token, context)
+ }
+ }
+ return
+}
+
+func (t *Tree) parseControl(context string) (lineNum int, pipe *PipeNode, list, elseList *ListNode) {
+ lineNum = t.lex.lineNumber()
+ defer t.popVars(len(t.vars))
+ pipe = t.pipeline(context)
+ var next Node
+ list, next = t.itemList(false)
+ switch next.Type() {
+ case nodeEnd: //done
+ case nodeElse:
+ elseList, next = t.itemList(false)
+ if next.Type() != nodeEnd {
+ t.errorf("expected end; found %s", next)
+ }
+ elseList = elseList
+ }
+ return lineNum, pipe, list, elseList
+}
+
+// If:
+// {{if pipeline}} itemList {{end}}
+// {{if pipeline}} itemList {{else}} itemList {{end}}
+// If keyword is past.
+func (t *Tree) ifControl() Node {
+ return newIf(t.parseControl("if"))
+}
+
+// Range:
+// {{range pipeline}} itemList {{end}}
+// {{range pipeline}} itemList {{else}} itemList {{end}}
+// Range keyword is past.
+func (t *Tree) rangeControl() Node {
+ return newRange(t.parseControl("range"))
+}
+
+// With:
+// {{with pipeline}} itemList {{end}}
+// {{with pipeline}} itemList {{else}} itemList {{end}}
+// If keyword is past.
+func (t *Tree) withControl() Node {
+ return newWith(t.parseControl("with"))
+}
+
+// End:
+// {{end}}
+// End keyword is past.
+func (t *Tree) endControl() Node {
+ t.expect(itemRightDelim, "end")
+ return newEnd()
+}
+
+// Else:
+// {{else}}
+// Else keyword is past.
+func (t *Tree) elseControl() Node {
+ t.expect(itemRightDelim, "else")
+ return newElse(t.lex.lineNumber())
+}
+
+// Template:
+// {{template stringValue pipeline}}
+// Template keyword is past. The name must be something that can evaluate
+// to a string.
+func (t *Tree) templateControl() Node {
+ var name string
+ switch token := t.next(); token.typ {
+ case itemString, itemRawString:
+ s, err := strconv.Unquote(token.val)
+ if err != nil {
+ t.error(err)
+ }
+ name = s
+ default:
+ t.unexpected(token, "template invocation")
+ }
+ var pipe *PipeNode
+ if t.next().typ != itemRightDelim {
+ t.backup()
+ // Do not pop variables; they persist until "end".
+ pipe = t.pipeline("template")
+ }
+ return newTemplate(t.lex.lineNumber(), name, pipe)
+}
+
+// command:
+// space-separated arguments up to a pipeline character or right delimiter.
+// we consume the pipe character but leave the right delim to terminate the action.
+func (t *Tree) command() *CommandNode {
+ cmd := newCommand()
+Loop:
+ for {
+ switch token := t.next(); token.typ {
+ case itemRightDelim:
+ t.backup()
+ break Loop
+ case itemPipe:
+ break Loop
+ case itemError:
+ t.errorf("%s", token.val)
+ case itemIdentifier:
+ if !t.hasFunction(token.val) {
+ t.errorf("function %q not defined", token.val)
+ }
+ cmd.append(NewIdentifier(token.val))
+ case itemDot:
+ cmd.append(newDot())
+ case itemVariable:
+ cmd.append(t.useVar(token.val))
+ case itemField:
+ cmd.append(newField(token.val))
+ case itemBool:
+ cmd.append(newBool(token.val == "true"))
+ case itemCharConstant, itemComplex, itemNumber:
+ number, err := newNumber(token.val, token.typ)
+ if err != nil {
+ t.error(err)
+ }
+ cmd.append(number)
+ case itemString, itemRawString:
+ s, err := strconv.Unquote(token.val)
+ if err != nil {
+ t.error(err)
+ }
+ cmd.append(newString(token.val, s))
+ default:
+ t.unexpected(token, "command")
+ }
+ }
+ if len(cmd.Args) == 0 {
+ t.errorf("empty command")
+ }
+ return cmd
+}
+
+// hasFunction reports if a function name exists in the Tree's maps.
+func (t *Tree) hasFunction(name string) bool {
+ for _, funcMap := range t.funcs {
+ if funcMap == nil {
+ continue
+ }
+ if funcMap[name] != nil {
+ return true
+ }
+ }
+ return false
+}
+
+// popVars trims the variable list to the specified length
+func (t *Tree) popVars(n int) {
+ t.vars = t.vars[:n]
+}
+
+// useVar returns a node for a variable reference. It errors if the
+// variable is not defined.
+func (t *Tree) useVar(name string) Node {
+ v := newVariable(name)
+ for _, varName := range t.vars {
+ if varName == v.Ident[0] {
+ return v
+ }
+ }
+ t.errorf("undefined variable %q", v.Ident[0])
+ return nil
+}
diff --git a/libgo/go/template/parse/parse_test.go b/libgo/go/template/parse/parse_test.go
new file mode 100644
index 00000000000..1928c319dec
--- /dev/null
+++ b/libgo/go/template/parse/parse_test.go
@@ -0,0 +1,259 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parse
+
+import (
+ "flag"
+ "fmt"
+ "testing"
+)
+
+var debug = flag.Bool("debug", false, "show the errors produced by the tests")
+
+type numberTest struct {
+ text string
+ isInt bool
+ isUint bool
+ isFloat bool
+ isComplex bool
+ int64
+ uint64
+ float64
+ complex128
+}
+
+var numberTests = []numberTest{
+ // basics
+ {"0", true, true, true, false, 0, 0, 0, 0},
+ {"-0", true, true, true, false, 0, 0, 0, 0}, // check that -0 is a uint.
+ {"73", true, true, true, false, 73, 73, 73, 0},
+ {"073", true, true, true, false, 073, 073, 073, 0},
+ {"0x73", true, true, true, false, 0x73, 0x73, 0x73, 0},
+ {"-73", true, false, true, false, -73, 0, -73, 0},
+ {"+73", true, false, true, false, 73, 0, 73, 0},
+ {"100", true, true, true, false, 100, 100, 100, 0},
+ {"1e9", true, true, true, false, 1e9, 1e9, 1e9, 0},
+ {"-1e9", true, false, true, false, -1e9, 0, -1e9, 0},
+ {"-1.2", false, false, true, false, 0, 0, -1.2, 0},
+ {"1e19", false, true, true, false, 0, 1e19, 1e19, 0},
+ {"-1e19", false, false, true, false, 0, 0, -1e19, 0},
+ {"4i", false, false, false, true, 0, 0, 0, 4i},
+ {"-1.2+4.2i", false, false, false, true, 0, 0, 0, -1.2 + 4.2i},
+ {"073i", false, false, false, true, 0, 0, 0, 73i}, // not octal!
+ // complex with 0 imaginary are float (and maybe integer)
+ {"0i", true, true, true, true, 0, 0, 0, 0},
+ {"-1.2+0i", false, false, true, true, 0, 0, -1.2, -1.2},
+ {"-12+0i", true, false, true, true, -12, 0, -12, -12},
+ {"13+0i", true, true, true, true, 13, 13, 13, 13},
+ // funny bases
+ {"0123", true, true, true, false, 0123, 0123, 0123, 0},
+ {"-0x0", true, true, true, false, 0, 0, 0, 0},
+ {"0xdeadbeef", true, true, true, false, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0},
+ // character constants
+ {`'a'`, true, true, true, false, 'a', 'a', 'a', 0},
+ {`'\n'`, true, true, true, false, '\n', '\n', '\n', 0},
+ {`'\\'`, true, true, true, false, '\\', '\\', '\\', 0},
+ {`'\''`, true, true, true, false, '\'', '\'', '\'', 0},
+ {`'\xFF'`, true, true, true, false, 0xFF, 0xFF, 0xFF, 0},
+ {`'パ'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+ {`'\u30d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+ {`'\U000030d1'`, true, true, true, false, 0x30d1, 0x30d1, 0x30d1, 0},
+ // some broken syntax
+ {text: "+-2"},
+ {text: "0x123."},
+ {text: "1e."},
+ {text: "0xi."},
+ {text: "1+2."},
+ {text: "'x"},
+ {text: "'xx'"},
+}
+
+func TestNumberParse(t *testing.T) {
+ for _, test := range numberTests {
+ // If fmt.Sscan thinks it's complex, it's complex. We can't trust the output
+ // because imaginary comes out as a number.
+ var c complex128
+ typ := itemNumber
+ if test.text[0] == '\'' {
+ typ = itemCharConstant
+ } else {
+ _, err := fmt.Sscan(test.text, &c)
+ if err == nil {
+ typ = itemComplex
+ }
+ }
+ n, err := newNumber(test.text, typ)
+ ok := test.isInt || test.isUint || test.isFloat || test.isComplex
+ if ok && err != nil {
+ t.Errorf("unexpected error for %q: %s", test.text, err)
+ continue
+ }
+ if !ok && err == nil {
+ t.Errorf("expected error for %q", test.text)
+ continue
+ }
+ if !ok {
+ if *debug {
+ fmt.Printf("%s\n\t%s\n", test.text, err)
+ }
+ continue
+ }
+ if n.IsComplex != test.isComplex {
+ t.Errorf("complex incorrect for %q; should be %t", test.text, test.isComplex)
+ }
+ if test.isInt {
+ if !n.IsInt {
+ t.Errorf("expected integer for %q", test.text)
+ }
+ if n.Int64 != test.int64 {
+ t.Errorf("int64 for %q should be %d Is %d", test.text, test.int64, n.Int64)
+ }
+ } else if n.IsInt {
+ t.Errorf("did not expect integer for %q", test.text)
+ }
+ if test.isUint {
+ if !n.IsUint {
+ t.Errorf("expected unsigned integer for %q", test.text)
+ }
+ if n.Uint64 != test.uint64 {
+ t.Errorf("uint64 for %q should be %d Is %d", test.text, test.uint64, n.Uint64)
+ }
+ } else if n.IsUint {
+ t.Errorf("did not expect unsigned integer for %q", test.text)
+ }
+ if test.isFloat {
+ if !n.IsFloat {
+ t.Errorf("expected float for %q", test.text)
+ }
+ if n.Float64 != test.float64 {
+ t.Errorf("float64 for %q should be %g Is %g", test.text, test.float64, n.Float64)
+ }
+ } else if n.IsFloat {
+ t.Errorf("did not expect float for %q", test.text)
+ }
+ if test.isComplex {
+ if !n.IsComplex {
+ t.Errorf("expected complex for %q", test.text)
+ }
+ if n.Complex128 != test.complex128 {
+ t.Errorf("complex128 for %q should be %g Is %g", test.text, test.complex128, n.Complex128)
+ }
+ } else if n.IsComplex {
+ t.Errorf("did not expect complex for %q", test.text)
+ }
+ }
+}
+
+type parseTest struct {
+ name string
+ input string
+ ok bool
+ result string
+}
+
+const (
+ noError = true
+ hasError = false
+)
+
+var parseTests = []parseTest{
+ {"empty", "", noError,
+ `[]`},
+ {"comment", "{{/*\n\n\n*/}}", noError,
+ `[]`},
+ {"spaces", " \t\n", noError,
+ `[(text: " \t\n")]`},
+ {"text", "some text", noError,
+ `[(text: "some text")]`},
+ {"emptyAction", "{{}}", hasError,
+ `[(action: [])]`},
+ {"field", "{{.X}}", noError,
+ `[(action: [(command: [F=[X]])])]`},
+ {"simple command", "{{printf}}", noError,
+ `[(action: [(command: [I=printf])])]`},
+ {"$ invocation", "{{$}}", noError,
+ "[(action: [(command: [V=[$]])])]"},
+ {"variable invocation", "{{with $x := 3}}{{$x 23}}{{end}}", noError,
+ "[({{with [V=[$x]] := [(command: [N=3])]}} [(action: [(command: [V=[$x] N=23])])])]"},
+ {"variable with fields", "{{$.I}}", noError,
+ "[(action: [(command: [V=[$ I]])])]"},
+ {"multi-word command", "{{printf `%d` 23}}", noError,
+ "[(action: [(command: [I=printf S=`%d` N=23])])]"},
+ {"pipeline", "{{.X|.Y}}", noError,
+ `[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`},
+ {"pipeline with decl", "{{$x := .X|.Y}}", noError,
+ `[(action: [V=[$x]] := [(command: [F=[X]]) (command: [F=[Y]])])]`},
+ {"declaration", "{{.X|.Y}}", noError,
+ `[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`},
+ {"simple if", "{{if .X}}hello{{end}}", noError,
+ `[({{if [(command: [F=[X]])]}} [(text: "hello")])]`},
+ {"if with else", "{{if .X}}true{{else}}false{{end}}", noError,
+ `[({{if [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ {"simple range", "{{range .X}}hello{{end}}", noError,
+ `[({{range [(command: [F=[X]])]}} [(text: "hello")])]`},
+ {"chained field range", "{{range .X.Y.Z}}hello{{end}}", noError,
+ `[({{range [(command: [F=[X Y Z]])]}} [(text: "hello")])]`},
+ {"nested range", "{{range .X}}hello{{range .Y}}goodbye{{end}}{{end}}", noError,
+ `[({{range [(command: [F=[X]])]}} [(text: "hello")({{range [(command: [F=[Y]])]}} [(text: "goodbye")])])]`},
+ {"range with else", "{{range .X}}true{{else}}false{{end}}", noError,
+ `[({{range [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ {"range over pipeline", "{{range .X|.M}}true{{else}}false{{end}}", noError,
+ `[({{range [(command: [F=[X]]) (command: [F=[M]])]}} [(text: "true")] {{else}} [(text: "false")])]`},
+ {"range []int", "{{range .SI}}{{.}}{{end}}", noError,
+ `[({{range [(command: [F=[SI]])]}} [(action: [(command: [{{<.>}}])])])]`},
+ {"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError,
+ `[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false N='a'])]}} [])]`},
+ {"template", "{{template `x`}}", noError,
+ `[{{template "x"}}]`},
+ {"template with arg", "{{template `x` .Y}}", noError,
+ `[{{template "x" [(command: [F=[Y]])]}}]`},
+ {"with", "{{with .X}}hello{{end}}", noError,
+ `[({{with [(command: [F=[X]])]}} [(text: "hello")])]`},
+ {"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError,
+ `[({{with [(command: [F=[X]])]}} [(text: "hello")] {{else}} [(text: "goodbye")])]`},
+ // Errors.
+ {"unclosed action", "hello{{range", hasError, ""},
+ {"unmatched end", "{{end}}", hasError, ""},
+ {"missing end", "hello{{range .x}}", hasError, ""},
+ {"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
+ {"undefined function", "hello{{undefined}}", hasError, ""},
+ {"undefined variable", "{{$x}}", hasError, ""},
+ {"variable undefined after end", "{{with $x := 4}}{{end}}{{$x}}", hasError, ""},
+ {"variable undefined in template", "{{template $v}}", hasError, ""},
+ {"declare with field", "{{with $x.Y := 4}}{{end}}", hasError, ""},
+ {"template with field ref", "{{template .X}}", hasError, ""},
+ {"template with var", "{{template $v}}", hasError, ""},
+ {"invalid punctuation", "{{printf 3, 4}}", hasError, ""},
+ {"multidecl outside range", "{{with $v, $u := 3}}{{end}}", hasError, ""},
+ {"too many decls in range", "{{range $u, $v, $w := 3}}{{end}}", hasError, ""},
+}
+
+var builtins = map[string]interface{}{
+ "printf": fmt.Sprintf,
+}
+
+func TestParse(t *testing.T) {
+ for _, test := range parseTests {
+ tmpl, err := New(test.name).Parse(test.input, builtins)
+ switch {
+ case err == nil && !test.ok:
+ t.Errorf("%q: expected error; got none", test.name)
+ continue
+ case err != nil && test.ok:
+ t.Errorf("%q: unexpected error: %v", test.name, err)
+ continue
+ case err != nil && !test.ok:
+ // expected error, got one
+ if *debug {
+ fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+ }
+ continue
+ }
+ result := tmpl.Root.String()
+ if result != test.result {
+ t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.result)
+ }
+ }
+}
diff --git a/libgo/go/template/parse/set.go b/libgo/go/template/parse/set.go
new file mode 100644
index 00000000000..dca41ea76cd
--- /dev/null
+++ b/libgo/go/template/parse/set.go
@@ -0,0 +1,50 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package parse
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+)
+
+// Set returns a slice of Trees created by parsing the template set
+// definition in the argument string. If an error is encountered,
+// parsing stops and an empty slice is returned with the error.
+func Set(text string, funcs ...map[string]interface{}) (tree map[string]*Tree, err os.Error) {
+ tree = make(map[string]*Tree)
+ defer (*Tree)(nil).recover(&err)
+ lex := lex("set", text)
+ const context = "define clause"
+ for {
+ t := New("set") // name will be updated once we know it.
+ t.startParse(funcs, lex)
+ // Expect EOF or "{{ define name }}".
+ if t.atEOF() {
+ break
+ }
+ t.expect(itemLeftDelim, context)
+ t.expect(itemDefine, context)
+ name := t.expect(itemString, context)
+ t.Name, err = strconv.Unquote(name.val)
+ if err != nil {
+ t.error(err)
+ }
+ t.expect(itemRightDelim, context)
+ end := t.parse(false)
+ if end == nil {
+ t.errorf("unexpected EOF in %s", context)
+ }
+ if end.Type() != nodeEnd {
+ t.errorf("unexpected %s in %s", end, context)
+ }
+ t.stopParse()
+ if _, present := tree[t.Name]; present {
+ return nil, fmt.Errorf("template: %q multiply defined", name)
+ }
+ tree[t.Name] = t
+ }
+ return
+}
diff --git a/libgo/go/template/set.go b/libgo/go/template/set.go
new file mode 100644
index 00000000000..f778fd1693f
--- /dev/null
+++ b/libgo/go/template/set.go
@@ -0,0 +1,108 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "template/parse"
+)
+
+// Set holds a set of related templates that can refer to one another by name.
+// The zero value represents an empty set.
+// A template may be a member of multiple sets.
+type Set struct {
+ tmpl map[string]*Template
+ parseFuncs FuncMap
+ execFuncs map[string]reflect.Value
+}
+
+func (s *Set) init() {
+ if s.tmpl == nil {
+ s.tmpl = make(map[string]*Template)
+ s.parseFuncs = make(FuncMap)
+ s.execFuncs = make(map[string]reflect.Value)
+ }
+}
+
+// Funcs adds the elements of the argument map to the set's function map. It
+// panics if a value in the map is not a function with appropriate return
+// type.
+// The return value is the set, so calls can be chained.
+func (s *Set) Funcs(funcMap FuncMap) *Set {
+ s.init()
+ addValueFuncs(s.execFuncs, funcMap)
+ addFuncs(s.parseFuncs, funcMap)
+ return s
+}
+
+// Add adds the argument templates to the set. It panics if two templates
+// with the same name are added or if a template is already a member of
+// a set.
+// The return value is the set, so calls can be chained.
+func (s *Set) Add(templates ...*Template) *Set {
+ for _, t := range templates {
+ if err := s.add(t); err != nil {
+ panic(err)
+ }
+ }
+ return s
+}
+
+// add adds the argument template to the set.
+func (s *Set) add(t *Template) os.Error {
+ s.init()
+ if t.set != nil {
+ return fmt.Errorf("template: %q already in a set", t.name)
+ }
+ if _, ok := s.tmpl[t.name]; ok {
+ return fmt.Errorf("template: %q already defined in set", t.name)
+ }
+ s.tmpl[t.name] = t
+ t.set = s
+ return nil
+}
+
+// Template returns the template with the given name in the set,
+// or nil if there is no such template.
+func (s *Set) Template(name string) *Template {
+ return s.tmpl[name]
+}
+
+// FuncMap returns the set's function map.
+func (s *Set) FuncMap() FuncMap {
+ return s.parseFuncs
+}
+
+// Execute applies the named template to the specified data object, writing
+// the output to wr.
+func (s *Set) Execute(wr io.Writer, name string, data interface{}) os.Error {
+ tmpl := s.tmpl[name]
+ if tmpl == nil {
+ return fmt.Errorf("template: no template %q in set", name)
+ }
+ return tmpl.Execute(wr, data)
+}
+
+// Parse parses a string into a set of named templates. Parse may be called
+// multiple times for a given set, adding the templates defined in the string
+// to the set. If a template is redefined, the element in the set is
+// overwritten with the new definition.
+func (s *Set) Parse(text string) (*Set, os.Error) {
+ trees, err := parse.Set(text, s.parseFuncs, builtins)
+ if err != nil {
+ return nil, err
+ }
+ s.init()
+ for name, tree := range trees {
+ tmpl := New(name)
+ tmpl.Tree = tree
+ tmpl.addToSet(s)
+ s.tmpl[name] = tmpl
+ }
+ return s, nil
+}
diff --git a/libgo/go/template/set_test.go b/libgo/go/template/set_test.go
new file mode 100644
index 00000000000..f437bc779c2
--- /dev/null
+++ b/libgo/go/template/set_test.go
@@ -0,0 +1,239 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "testing"
+)
+
+const (
+ noError = true
+ hasError = false
+)
+
+type setParseTest struct {
+ name string
+ input string
+ ok bool
+ names []string
+ results []string
+}
+
+var setParseTests = []setParseTest{
+ {"empty", "", noError,
+ nil,
+ nil},
+ {"one", `{{define "foo"}} FOO {{end}}`, noError,
+ []string{"foo"},
+ []string{`[(text: " FOO ")]`}},
+ {"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
+ []string{"foo", "bar"},
+ []string{`[(text: " FOO ")]`, `[(text: " BAR ")]`}},
+ // errors
+ {"missing end", `{{define "foo"}} FOO `, hasError,
+ nil,
+ nil},
+ {"malformed name", `{{define "foo}} FOO `, hasError,
+ nil,
+ nil},
+}
+
+func TestSetParse(t *testing.T) {
+ for _, test := range setParseTests {
+ set, err := new(Set).Parse(test.input)
+ switch {
+ case err == nil && !test.ok:
+ t.Errorf("%q: expected error; got none", test.name)
+ continue
+ case err != nil && test.ok:
+ t.Errorf("%q: unexpected error: %v", test.name, err)
+ continue
+ case err != nil && !test.ok:
+ // expected error, got one
+ if *debug {
+ fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+ }
+ continue
+ }
+ if set == nil {
+ continue
+ }
+ if len(set.tmpl) != len(test.names) {
+ t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(set.tmpl))
+ continue
+ }
+ for i, name := range test.names {
+ tmpl, ok := set.tmpl[name]
+ if !ok {
+ t.Errorf("%s: can't find template %q", test.name, name)
+ continue
+ }
+ result := tmpl.Root.String()
+ if result != test.results[i] {
+ t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
+ }
+ }
+ }
+}
+
+var setExecTests = []execTest{
+ {"empty", "", "", nil, true},
+ {"text", "some text", "some text", nil, true},
+ {"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
+ {"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
+ {"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
+ {"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
+ {"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
+ {"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
+ {"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
+
+ // User-defined function: test argument evaluator.
+ {"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
+ {"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
+}
+
+// These strings are also in testdata/*.
+const setText1 = `
+ {{define "x"}}TEXT{{end}}
+ {{define "dotV"}}{{.V}}{{end}}
+`
+
+const setText2 = `
+ {{define "dot"}}{{.}}{{end}}
+ {{define "nested"}}{{template "dot" .}}{{end}}
+`
+
+func TestSetExecute(t *testing.T) {
+ // Declare a set with a couple of templates first.
+ set := new(Set)
+ _, err := set.Parse(setText1)
+ if err != nil {
+ t.Fatalf("error parsing set: %s", err)
+ }
+ _, err = set.Parse(setText2)
+ if err != nil {
+ t.Fatalf("error parsing set: %s", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+func TestSetParseFiles(t *testing.T) {
+ set := new(Set)
+ _, err := set.ParseFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = set.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+func TestParseSetFiles(t *testing.T) {
+ set := new(Set)
+ _, err := ParseSetFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ set, err = ParseSetFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+func TestSetParseGlob(t *testing.T) {
+ _, err := new(Set).ParseGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = new(Set).ParseGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ set, err := new(Set).ParseGlob("testdata/file*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+func TestParseSetGlob(t *testing.T) {
+ _, err := ParseSetGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = ParseSetGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ set, err := ParseSetGlob("testdata/file*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(setExecTests, set, t)
+}
+
+var templateFileExecTests = []execTest{
+ {"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\ntemplate2\n", 0, true},
+}
+
+func TestSetParseTemplateFiles(t *testing.T) {
+ _, err := ParseTemplateFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ set, err := new(Set).ParseTemplateFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, set, t)
+}
+
+func TestParseTemplateFiles(t *testing.T) {
+ _, err := ParseTemplateFiles("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ set, err := new(Set).ParseTemplateFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, set, t)
+}
+
+func TestSetParseTemplateGlob(t *testing.T) {
+ _, err := ParseTemplateGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = new(Set).ParseTemplateGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ set, err := new(Set).ParseTemplateGlob("testdata/tmpl*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, set, t)
+}
+
+func TestParseTemplateGlob(t *testing.T) {
+ _, err := ParseTemplateGlob("DOES NOT EXIST")
+ if err == nil {
+ t.Error("expected error for non-existent file; got none")
+ }
+ _, err = ParseTemplateGlob("[x")
+ if err == nil {
+ t.Error("expected error for bad pattern; got none")
+ }
+ set, err := ParseTemplateGlob("testdata/tmpl*.tmpl")
+ if err != nil {
+ t.Fatalf("error parsing files: %v", err)
+ }
+ testExecute(templateFileExecTests, set, t)
+}
diff --git a/libgo/go/template/testdata/file1.tmpl b/libgo/go/template/testdata/file1.tmpl
new file mode 100644
index 00000000000..febf9d9f89d
--- /dev/null
+++ b/libgo/go/template/testdata/file1.tmpl
@@ -0,0 +1,2 @@
+{{define "x"}}TEXT{{end}}
+{{define "dotV"}}{{.V}}{{end}}
diff --git a/libgo/go/template/testdata/file2.tmpl b/libgo/go/template/testdata/file2.tmpl
new file mode 100644
index 00000000000..39bf6fb9eef
--- /dev/null
+++ b/libgo/go/template/testdata/file2.tmpl
@@ -0,0 +1,2 @@
+{{define "dot"}}{{.}}{{end}}
+{{define "nested"}}{{template "dot" .}}{{end}}
diff --git a/libgo/go/template/testdata/tmpl1.tmpl b/libgo/go/template/testdata/tmpl1.tmpl
new file mode 100644
index 00000000000..3d15b81735a
--- /dev/null
+++ b/libgo/go/template/testdata/tmpl1.tmpl
@@ -0,0 +1 @@
+template1
diff --git a/libgo/go/template/testdata/tmpl2.tmpl b/libgo/go/template/testdata/tmpl2.tmpl
new file mode 100644
index 00000000000..a374d2fe7fc
--- /dev/null
+++ b/libgo/go/template/testdata/tmpl2.tmpl
@@ -0,0 +1 @@
+template2
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go
index cf73e2b48f8..fd0bd866578 100644
--- a/libgo/go/testing/benchmark.go
+++ b/libgo/go/testing/benchmark.go
@@ -13,6 +13,7 @@ import (
)
var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run")
+var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds")
// An internal type but exported because it is cross-package; part of the implementation
// of gotest.
@@ -34,7 +35,11 @@ type B struct {
// 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() }
+func (b *B) StartTimer() {
+ if b.start == 0 {
+ 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
@@ -46,9 +51,12 @@ func (b *B) StopTimer() {
b.start = 0
}
-// ResetTimer stops the timer and sets the elapsed benchmark time to zero.
+// ResetTimer sets the elapsed benchmark time to zero.
+// It does not affect whether the timer is running.
func (b *B) ResetTimer() {
- b.start = 0
+ if b.start > 0 {
+ b.start = time.Nanoseconds()
+ }
b.ns = 0
}
@@ -125,14 +133,15 @@ 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 {
+ // Run the benchmark for at least the specified amount of time.
+ time := int64(*benchTime * 1e9)
+ for b.ns < time && n < 1e9 {
last := n
// Predict iterations/sec.
if b.nsPerOp() == 0 {
n = 1e9
} else {
- n = 1e9 / int(b.nsPerOp())
+ n = int(time / 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.
@@ -143,14 +152,13 @@ func (b *B) run() BenchmarkResult {
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.
+ Bytes int64 // Bytes processed in one iteration.
}
func (r BenchmarkResult) NsPerOp() int64 {
@@ -160,13 +168,31 @@ func (r BenchmarkResult) NsPerOp() int64 {
return r.Ns / int64(r.N)
}
+func (r BenchmarkResult) mbPerSec() float64 {
+ if r.Bytes <= 0 || r.Ns <= 0 || r.N <= 0 {
+ return 0
+ }
+ return float64(r.Bytes) * float64(r.N) / float64(r.Ns) * 1e3
+}
+
func (r BenchmarkResult) String() string {
- ns := r.NsPerOp()
+ mbs := r.mbPerSec()
mb := ""
- if ns > 0 && r.Bytes > 0 {
- mb = fmt.Sprintf("\t%7.2f MB/s", (float64(r.Bytes)/1e6)/(float64(ns)/1e9))
+ if mbs != 0 {
+ mb = fmt.Sprintf("\t%7.2f MB/s", mbs)
}
- return fmt.Sprintf("%8d\t%10d ns/op%s", r.N, ns, mb)
+ nsop := r.NsPerOp()
+ ns := fmt.Sprintf("%10d ns/op", nsop)
+ if r.N > 0 && nsop < 100 {
+ // The format specifiers here make sure that
+ // the ones digits line up for all three possible formats.
+ if nsop < 10 {
+ ns = fmt.Sprintf("%13.2f ns/op", float64(r.Ns)/float64(r.N))
+ } else {
+ ns = fmt.Sprintf("%12.1f ns/op", float64(r.Ns)/float64(r.N))
+ }
+ }
+ return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb)
}
// An internal function but exported because it is cross-package; part of the implementation
@@ -185,9 +211,20 @@ func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmark
if !matched {
continue
}
- b := &B{benchmark: Benchmark}
- r := b.run()
- fmt.Printf("%s\t%v\n", Benchmark.Name, r)
+ for _, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ b := &B{benchmark: Benchmark}
+ benchName := Benchmark.Name
+ if procs != 1 {
+ benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
+ }
+ print(fmt.Sprintf("%s\t", benchName))
+ r := b.run()
+ print(fmt.Sprintf("%v\n", r))
+ if p := runtime.GOMAXPROCS(-1); p != procs {
+ print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", benchName, p))
+ }
+ }
}
}
diff --git a/libgo/go/testing/iotest/reader.go b/libgo/go/testing/iotest/reader.go
index e4003d74450..dcf5565e073 100644
--- a/libgo/go/testing/iotest/reader.go
+++ b/libgo/go/testing/iotest/reader.go
@@ -37,7 +37,6 @@ 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.
@@ -58,7 +57,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
r.unread = r.data[0:n1]
err = err1
}
- if n > 0 {
+ if n > 0 || err != nil {
break
}
n = copy(p, r.unread)
@@ -66,3 +65,22 @@ func (r *dataErrReader) Read(p []byte) (n int, err os.Error) {
}
return
}
+
+var ErrTimeout = os.NewError("timeout")
+
+// TimeoutReader returns ErrTimeout on the second read
+// with no data. Subsequent calls to read succeed.
+func TimeoutReader(r io.Reader) io.Reader { return &timeoutReader{r, 0} }
+
+type timeoutReader struct {
+ r io.Reader
+ count int
+}
+
+func (r *timeoutReader) Read(p []byte) (int, os.Error) {
+ r.count++
+ if r.count == 2 {
+ return 0, ErrTimeout
+ }
+ return r.r.Read(p)
+}
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index 8781b207def..ec4a4537176 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -44,6 +44,8 @@ import (
"os"
"runtime"
"runtime/pprof"
+ "strings"
+ "strconv"
"time"
)
@@ -62,6 +64,9 @@ var (
memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
timeout = flag.Int64("test.timeout", 0, "if > 0, sets time limit for tests in seconds")
+ cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
+
+ cpuList []int
)
// Short reports whether the -test.short flag is set.
@@ -69,7 +74,6 @@ func Short() bool {
return *short
}
-
// Insert final newline if needed and tabs after internal newlines.
func tabify(s string) string {
n := len(s)
@@ -157,6 +161,7 @@ func tRunner(t *T, test *InternalTest) {
// of gotest.
func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest, benchmarks []InternalBenchmark) {
flag.Parse()
+ parseCpuList()
before()
startAlarm()
@@ -180,23 +185,34 @@ func RunTests(matchString func(pat, str string) (bool, os.Error), tests []Intern
if !matched {
continue
}
- if *chatty {
- println("=== RUN ", tests[i].Name)
- }
- ns := -time.Nanoseconds()
- t := new(T)
- t.ch = make(chan *T)
- go tRunner(t, &tests[i])
- <-t.ch
- ns += time.Nanoseconds()
- tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
- if t.failed {
- println("--- FAIL:", tests[i].Name, tstr)
- print(t.errors)
- ok = false
- } else if *chatty {
- println("--- PASS:", tests[i].Name, tstr)
- print(t.errors)
+ for _, procs := range cpuList {
+ runtime.GOMAXPROCS(procs)
+ testName := tests[i].Name
+ if procs != 1 {
+ testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
+ }
+ if *chatty {
+ println("=== RUN ", testName)
+ }
+ ns := -time.Nanoseconds()
+ t := new(T)
+ t.ch = make(chan *T)
+ go tRunner(t, &tests[i])
+ <-t.ch
+ ns += time.Nanoseconds()
+ tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
+ if p := runtime.GOMAXPROCS(-1); t.failed == false && p != procs {
+ t.failed = true
+ t.errors = fmt.Sprintf("%s left GOMAXPROCS set to %d\n", testName, p)
+ }
+ if t.failed {
+ println("--- FAIL:", testName, tstr)
+ print(t.errors)
+ ok = false
+ } else if *chatty {
+ println("--- PASS:", testName, tstr)
+ print(t.errors)
+ }
}
}
if !ok {
@@ -265,3 +281,18 @@ func stopAlarm() {
func alarm() {
panic("test timed out")
}
+
+func parseCpuList() {
+ if len(*cpuListStr) == 0 {
+ cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
+ } else {
+ for _, val := range strings.Split(*cpuListStr, ",") {
+ cpu, err := strconv.Atoi(val)
+ if err != nil || cpu <= 0 {
+ println("invalid value for -test.cpu")
+ os.Exit(1)
+ }
+ cpuList = append(cpuList, cpu)
+ }
+ }
+}
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index 7b5a8f3b67f..5ddd54812f3 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -26,6 +26,12 @@ const (
// replaced by a digit if the following number (a day) has two digits; for
// compatibility with fixed-width Unix time formats.
//
+// A decimal point followed by one or more zeros represents a fractional
+// second. When parsing (only), the input may contain a fractional second
+// field immediately after the seconds field, even if the layout does not
+// signify its presence. In that case a decimal point followed by a maximal
+// series of digits is parsed as a fractional second.
+//
// Numeric time zone offsets format as follows:
// -0700 ±hhmm
// -07:00 ±hh:mm
@@ -45,6 +51,11 @@ const (
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC3339 = "2006-01-02T15:04:05Z07:00"
Kitchen = "3:04PM"
+ // Handy time stamps.
+ Stamp = "Jan _2 15:04:05"
+ StampMilli = "Jan _2 15:04:05.000"
+ StampMicro = "Jan _2 15:04:05.000000"
+ StampNano = "Jan _2 15:04:05.000000000"
)
const (
@@ -154,6 +165,16 @@ func nextStdChunk(layout string) (prefix, std, suffix string) {
if len(layout) >= i+6 && layout[i:i+6] == stdISO8601ColonTZ {
return layout[0:i], layout[i : i+6], layout[i+6:]
}
+ case '.': // .000 - multiple digits of zeros (only) for fractional seconds.
+ numZeros := 0
+ var j int
+ for j = i + 1; j < len(layout) && layout[j] == '0'; j++ {
+ numZeros++
+ }
+ // String of digits must end here - only fractional second is all zeros.
+ if numZeros > 0 && !isDigit(layout, j) {
+ return layout[0:i], layout[i : i+1+numZeros], layout[i+1+numZeros:]
+ }
}
}
return layout, "", ""
@@ -230,6 +251,21 @@ func pad(i int, padding string) string {
func zeroPad(i int) string { return pad(i, "0") }
+// formatNano formats a fractional second, as nanoseconds.
+func formatNano(nanosec, n int) string {
+ // User might give us bad data. Make sure it's positive and in range.
+ // They'll get nonsense output but it will have the right format.
+ s := strconv.Uitoa(uint(nanosec) % 1e9)
+ // Zero pad left without fmt.
+ if len(s) < 9 {
+ s = "000000000"[:9-len(s)] + s
+ }
+ if n > 9 {
+ n = 9
+ }
+ return "." + s[:n]
+}
+
// 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
@@ -248,7 +284,7 @@ func (t *Time) Format(layout string) string {
var p string
switch std {
case stdYear:
- p = strconv.Itoa64(t.Year % 100)
+ p = zeroPad(int(t.Year % 100))
case stdLongYear:
p = strconv.Itoa64(t.Year)
case stdMonth:
@@ -272,9 +308,19 @@ func (t *Time) Format(layout string) string {
case stdHour:
p = zeroPad(t.Hour)
case stdHour12:
- p = strconv.Itoa(t.Hour % 12)
+ // Noon is 12PM, midnight is 12AM.
+ hr := t.Hour % 12
+ if hr == 0 {
+ hr = 12
+ }
+ p = strconv.Itoa(hr)
case stdZeroHour12:
- p = zeroPad(t.Hour % 12)
+ // Noon is 12PM, midnight is 12AM.
+ hr := t.Hour % 12
+ if hr == 0 {
+ hr = 12
+ }
+ p = zeroPad(hr)
case stdMinute:
p = strconv.Itoa(t.Minute)
case stdZeroMinute:
@@ -330,6 +376,10 @@ func (t *Time) Format(layout string) string {
p += zeroPad(zone / 60)
p += zeroPad(zone % 60)
}
+ default:
+ if len(std) >= 2 && std[0:2] == ".0" {
+ p = formatNano(t.Nanosecond, len(std)-1)
+ }
}
b.WriteString(p)
layout = suffix
@@ -345,7 +395,7 @@ func (t *Time) String() string {
return t.Format(UnixDate)
}
-var errBad = os.ErrorString("bad") // just a marker; not returned to user
+var errBad = os.NewError("bad value for field") // placeholder not passed to user
// ParseError describes a problem parsing a time string.
type ParseError struct {
@@ -369,14 +419,24 @@ func (e *ParseError) String() string {
strconv.Quote(e.Value) + e.Message
}
+// isDigit returns true if s[i] is a decimal digit, false if not or
+// if s[i] is out of range.
+func isDigit(s string, i int) bool {
+ if len(s) <= i {
+ return false
+ }
+ c := s[i]
+ return '0' <= c && c <= '9'
+}
+
// 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' {
+ if !isDigit(s, 0) {
return 0, s, errBad
}
- if len(s) == 1 || s[1] < '0' || s[1] > '9' {
+ if !isDigit(s, 1) {
if fixed {
return 0, s, errBad
}
@@ -424,11 +484,12 @@ func skip(value, prefix string) (string, os.Error) {
// 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.
+// sane: hours in 0..23, minutes in 0..59, day of month in 1..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
+ amSet := false // do we need to subtract 12 from the hour for midnight?
pmSet := false // do we need to add 12 to the hour?
layout, value := alayout, avalue
// Each iteration processes one std value.
@@ -461,7 +522,7 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
t.Year += 2000
}
case stdLongYear:
- if len(value) < 4 || value[0] < '0' || value[0] > '9' {
+ if len(value) < 4 || !isDigit(value, 0) {
err = errBad
break
}
@@ -509,6 +570,21 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
if t.Second < 0 || 60 <= t.Second {
rangeErrString = "second"
}
+ // Special case: do we have a fractional second but no
+ // fractional second in the format?
+ if len(value) > 2 && value[0] == '.' && isDigit(value, 1) {
+ _, std, _ := nextStdChunk(layout)
+ if len(std) > 0 && std[0] == '.' && isDigit(std, 1) {
+ // Fractional second in the layout; proceed normally
+ break
+ }
+ // No fractional second in the layout but we have one in the input.
+ n := 2
+ for ; n < len(value) && isDigit(value, n); n++ {
+ }
+ rangeErrString, err = t.parseNanoseconds(value, n)
+ value = value[n:]
+ }
case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
value = value[1:]
@@ -558,9 +634,12 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
break
}
p, value = value[0:2], value[2:]
- if p == "PM" {
+ switch p {
+ case "PM":
pmSet = true
- } else if p != "AM" {
+ case "AM":
+ amSet = true
+ default:
err = errBad
}
case stdpm:
@@ -569,9 +648,12 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
break
}
p, value = value[0:2], value[2:]
- if p == "pm" {
+ switch p {
+ case "pm":
pmSet = true
- } else if p != "am" {
+ case "am":
+ amSet = true
+ default:
err = errBad
}
case stdTZ:
@@ -603,6 +685,15 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
if offset, found := lookupByName(p); found {
t.ZoneOffset = offset
}
+ default:
+ if len(value) < len(std) {
+ err = errBad
+ break
+ }
+ if len(std) >= 2 && std[0:2] == ".0" {
+ rangeErrString, err = t.parseNanoseconds(value, len(std))
+ value = value[len(std):]
+ }
}
if rangeErrString != "" {
return nil, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
@@ -613,6 +704,31 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
}
if pmSet && t.Hour < 12 {
t.Hour += 12
+ } else if amSet && t.Hour == 12 {
+ t.Hour = 0
}
return &t, nil
}
+
+func (t *Time) parseNanoseconds(value string, nbytes int) (rangErrString string, err os.Error) {
+ if value[0] != '.' {
+ return "", errBad
+ }
+ var ns int
+ ns, err = strconv.Atoi(value[1:nbytes])
+ if err != nil {
+ return "", err
+ }
+ if ns < 0 || 1e9 <= ns {
+ return "fractional second", nil
+ }
+ // We need nanoseconds, which means scaling by the number
+ // of missing digits in the format, maximum length 10. If it's
+ // longer than 10, we won't scale.
+ scaleDigits := 10 - nbytes
+ for i := 0; i < scaleDigits; i++ {
+ ns *= 10
+ }
+ t.Nanosecond = ns
+ return
+}
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
index 3bc253c94a3..314622d0dc9 100644
--- a/libgo/go/time/sleep.go
+++ b/libgo/go/time/sleep.go
@@ -91,7 +91,7 @@ func (e *Timer) Stop() (ok bool) {
// It assumes that f will not block.
func after(ns int64, f func(int64)) (e *Timer) {
now := Nanoseconds()
- t := Nanoseconds() + ns
+ t := now + ns
if ns > 0 && t < now {
panic("time: time overflow")
}
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index eb6bb25fd4d..9b59767af3d 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -173,7 +173,7 @@ func testAfterQueuing(t *testing.T) os.Error {
for _, slot := range slots {
go await(slot, result, After(int64(slot)*Delta))
}
- sort.SortInts(slots)
+ sort.Ints(slots)
for _, slot := range slots {
r := <-result
if r.slot != slot {
diff --git a/libgo/go/time/sys.go b/libgo/go/time/sys.go
index 63f4cbf3d77..9fde3b3b650 100644
--- a/libgo/go/time/sys.go
+++ b/libgo/go/time/sys.go
@@ -4,10 +4,7 @@
package time
-import (
- "os"
- "syscall"
-)
+import "os"
// Seconds reports the number of seconds since the Unix epoch,
// January 1, 1970 00:00:00 UTC.
@@ -52,11 +49,3 @@ func sleep(t, ns int64) (int64, os.Error) {
}
return t, nil
}
-
-func sysSleep(t int64) os.Error {
- errno := syscall.Sleep(t)
- if errno != 0 && errno != syscall.EINTR {
- return os.NewSyscallError("sleep", errno)
- }
- return nil
-}
diff --git a/libgo/go/time/sys_plan9.go b/libgo/go/time/sys_plan9.go
new file mode 100644
index 00000000000..abe8649a24b
--- /dev/null
+++ b/libgo/go/time/sys_plan9.go
@@ -0,0 +1,18 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "os"
+ "syscall"
+)
+
+func sysSleep(t int64) os.Error {
+ err := syscall.Sleep(t)
+ if err != nil {
+ return os.NewSyscallError("sleep", err)
+ }
+ return nil
+}
diff --git a/libgo/go/time/sys_posix.go b/libgo/go/time/sys_posix.go
new file mode 100644
index 00000000000..0d1eb72fcf5
--- /dev/null
+++ b/libgo/go/time/sys_posix.go
@@ -0,0 +1,18 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "os"
+ "syscall"
+)
+
+func sysSleep(t int64) os.Error {
+ errno := syscall.Sleep(t)
+ if errno != 0 && errno != syscall.EINTR {
+ return os.NewSyscallError("sleep", errno)
+ }
+ return nil
+}
diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go
index 6c21bf19b92..852bae9c935 100644
--- a/libgo/go/time/tick.go
+++ b/libgo/go/time/tick.go
@@ -88,7 +88,7 @@ func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
// 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.
+// signaling a time to wake up one or more Tickers.
func tickerLoop() {
// Represents the next alarm to be delivered.
var alarm alarmer
@@ -160,7 +160,7 @@ var onceStartTickerLoop sync.Once
// ns must be greater than zero; if not, NewTicker will panic.
func NewTicker(ns int64) *Ticker {
if ns <= 0 {
- panic(os.ErrorString("non-positive interval for NewTicker"))
+ panic(os.NewError("non-positive interval for NewTicker"))
}
c := make(chan int64, 1) // See comment on send in tickerLoop
t := &Ticker{
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index a0480786aa5..0e05da48447 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -21,6 +21,7 @@ type Time struct {
Year int64 // 2006 is 2006
Month, Day int // Jan-2 is 1, 2
Hour, Minute, Second int // 15:04:05 is 15, 4, 5.
+ Nanosecond int // Fractional second.
Weekday int // Sunday, Monday, ...
ZoneOffset int // seconds east of UTC, e.g. -7*60*60 for -0700
Zone string // e.g., "MST"
@@ -128,8 +129,19 @@ func SecondsToUTC(sec int64) *Time {
return t
}
+// NanosecondsToUTC converts nsec, in number of nanoseconds since the Unix epoch,
+// into a parsed Time value in the UTC time zone.
+func NanosecondsToUTC(nsec int64) *Time {
+ // This one calls SecondsToUTC rather than the other way around because
+ // that admits a much larger span of time; NanosecondsToUTC is limited
+ // to a few hundred years only.
+ t := SecondsToUTC(nsec / 1e9)
+ t.Nanosecond = int(nsec % 1e9)
+ return t
+}
+
// UTC returns the current time as a parsed Time value in the UTC time zone.
-func UTC() *Time { return SecondsToUTC(Seconds()) }
+func UTC() *Time { return NanosecondsToUTC(Nanoseconds()) }
// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
// into a parsed Time value in the local time zone.
@@ -141,8 +153,16 @@ func SecondsToLocalTime(sec int64) *Time {
return t
}
+// NanosecondsToLocalTime converts nsec, in number of nanoseconds since the Unix epoch,
+// into a parsed Time value in the local time zone.
+func NanosecondsToLocalTime(nsec int64) *Time {
+ t := SecondsToLocalTime(nsec / 1e9)
+ t.Nanosecond = int(nsec % 1e9)
+ return t
+}
+
// LocalTime returns the current time as a parsed Time value in the local time zone.
-func LocalTime() *Time { return SecondsToLocalTime(Seconds()) }
+func LocalTime() *Time { return NanosecondsToLocalTime(Nanoseconds()) }
// Seconds returns the number of seconds since January 1, 1970 represented by the
// parsed Time value.
@@ -202,3 +222,9 @@ func (t *Time) Seconds() int64 {
sec -= int64(t.ZoneOffset)
return sec
}
+
+// Nanoseconds returns the number of nanoseconds since January 1, 1970 represented by the
+// parsed Time value.
+func (t *Time) Nanoseconds() int64 {
+ return t.Seconds()*1e9 + int64(t.Nanosecond)
+}
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index 1d83291c097..dceed491aa0 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -6,6 +6,7 @@ package time_test
import (
"os"
+ "strconv"
"strings"
"testing"
"testing/quick"
@@ -37,21 +38,31 @@ type TimeTest struct {
}
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"}},
+ {0, Time{1970, 1, 1, 0, 0, 0, 0, Thursday, 0, "UTC"}},
+ {1221681866, Time{2008, 9, 17, 20, 4, 26, 0, Wednesday, 0, "UTC"}},
+ {-1221681866, Time{1931, 4, 16, 3, 55, 34, 0, Thursday, 0, "UTC"}},
+ {-11644473600, Time{1601, 1, 1, 0, 0, 0, 0, Monday, 0, "UTC"}},
+ {599529660, Time{1988, 12, 31, 0, 1, 0, 0, Saturday, 0, "UTC"}},
+ {978220860, Time{2000, 12, 31, 0, 1, 0, 0, Sunday, 0, "UTC"}},
+ {1e18, Time{31688740476, 10, 23, 1, 46, 40, 0, Friday, 0, "UTC"}},
+ {-1e18, Time{-31688736537, 3, 10, 22, 13, 20, 0, Tuesday, 0, "UTC"}},
+ {0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, 0, Sunday, 0, "UTC"}},
+ {-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, 0, Sunday, 0, "UTC"}},
+}
+
+var nanoutctests = []TimeTest{
+ {0, Time{1970, 1, 1, 0, 0, 0, 1e8, Thursday, 0, "UTC"}},
+ {1221681866, Time{2008, 9, 17, 20, 4, 26, 2e8, Wednesday, 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"}},
+ {0, Time{1969, 12, 31, 16, 0, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
+ {1221681866, Time{2008, 9, 17, 13, 4, 26, 0, Wednesday, -7 * 60 * 60, "PDT"}},
+}
+
+var nanolocaltests = []TimeTest{
+ {0, Time{1969, 12, 31, 16, 0, 0, 1e8, Wednesday, -8 * 60 * 60, "PST"}},
+ {1221681866, Time{2008, 9, 17, 13, 4, 26, 3e8, Wednesday, -7 * 60 * 60, "PDT"}},
}
func same(t, u *Time) bool {
@@ -61,15 +72,16 @@ func same(t, u *Time) bool {
t.Hour == u.Hour &&
t.Minute == u.Minute &&
t.Second == u.Second &&
+ t.Nanosecond == u.Nanosecond &&
t.Weekday == u.Weekday &&
t.ZoneOffset == u.ZoneOffset &&
t.Zone == u.Zone
}
func TestSecondsToUTC(t *testing.T) {
- for i := 0; i < len(utctests); i++ {
- sec := utctests[i].seconds
- golden := &utctests[i].golden
+ for _, test := range utctests {
+ sec := test.seconds
+ golden := &test.golden
tm := SecondsToUTC(sec)
newsec := tm.Seconds()
if newsec != sec {
@@ -83,10 +95,27 @@ func TestSecondsToUTC(t *testing.T) {
}
}
+func TestNanosecondsToUTC(t *testing.T) {
+ for _, test := range nanoutctests {
+ golden := &test.golden
+ nsec := test.seconds*1e9 + int64(golden.Nanosecond)
+ tm := NanosecondsToUTC(nsec)
+ newnsec := tm.Nanoseconds()
+ if newnsec != nsec {
+ t.Errorf("NanosecondsToUTC(%d).Nanoseconds() = %d", nsec, newnsec)
+ }
+ if !same(tm, golden) {
+ t.Errorf("NanosecondsToUTC(%d):", nsec)
+ t.Errorf(" want=%+v", *golden)
+ t.Errorf(" have=%+v", *tm)
+ }
+ }
+}
+
func TestSecondsToLocalTime(t *testing.T) {
- for i := 0; i < len(localtests); i++ {
- sec := localtests[i].seconds
- golden := &localtests[i].golden
+ for _, test := range localtests {
+ sec := test.seconds
+ golden := &test.golden
tm := SecondsToLocalTime(sec)
newsec := tm.Seconds()
if newsec != sec {
@@ -100,6 +129,23 @@ func TestSecondsToLocalTime(t *testing.T) {
}
}
+func TestNanoecondsToLocalTime(t *testing.T) {
+ for _, test := range nanolocaltests {
+ golden := &test.golden
+ nsec := test.seconds*1e9 + int64(golden.Nanosecond)
+ tm := NanosecondsToLocalTime(nsec)
+ newnsec := tm.Nanoseconds()
+ if newnsec != nsec {
+ t.Errorf("NanosecondsToLocalTime(%d).Seconds() = %d", nsec, newnsec)
+ }
+ if !same(tm, golden) {
+ t.Errorf("NanosecondsToLocalTime(%d):", nsec)
+ t.Errorf(" want=%+v", *golden)
+ t.Errorf(" have=%+v", *tm)
+ }
+ }
+}
+
func TestSecondsToUTCAndBack(t *testing.T) {
f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec }
f32 := func(sec int32) bool { return f(int64(sec)) }
@@ -114,15 +160,30 @@ func TestSecondsToUTCAndBack(t *testing.T) {
}
}
+func TestNanosecondsToUTCAndBack(t *testing.T) {
+ f := func(nsec int64) bool { return NanosecondsToUTC(nsec).Nanoseconds() == nsec }
+ f32 := func(nsec int32) bool { return f(int64(nsec)) }
+ cfg := &quick.Config{MaxCount: 10000}
+
+ // Try a small date first, then the large ones. (The span is only a few hundred years
+ // for nanoseconds in an int64.)
+ 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"},
+ {Time{2008, 9, 17, 20, 4, 26, 0, Wednesday, 0, "UTC"}, "2008-09-17T20:04:26Z"},
+ {Time{1994, 9, 17, 20, 4, 26, 0, Wednesday, -18000, "EST"}, "1994-09-17T20:04:26-05:00"},
+ {Time{2000, 12, 26, 1, 15, 6, 0, Wednesday, 15600, "OTO"}, "2000-12-26T01:15:06+04:20"},
}
func TestRFC3339Conversion(t *testing.T) {
@@ -142,21 +203,27 @@ type FormatTest struct {
}
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"},
+ {"ANSIC", ANSIC, "Wed Feb 4 21:00:57 2009"},
+ {"UnixDate", UnixDate, "Wed Feb 4 21:00:57 PST 2009"},
+ {"RubyDate", RubyDate, "Wed Feb 04 21:00:57 -0800 2009"},
+ {"RFC822", RFC822, "04 Feb 09 2100 PST"},
+ {"RFC850", RFC850, "Wednesday, 04-Feb-09 21:00:57 PST"},
+ {"RFC1123", RFC1123, "Wed, 04 Feb 2009 21:00:57 PST"},
+ {"RFC3339", RFC3339, "2009-02-04T21:00:57-08:00"},
{"Kitchen", Kitchen, "9:00PM"},
{"am/pm", "3pm", "9pm"},
{"AM/PM", "3PM", "9PM"},
+ {"two-digit year", "06 01 02", "09 02 04"},
+ // Time stamps, Fractional seconds.
+ {"Stamp", Stamp, "Feb 4 21:00:57"},
+ {"StampMilli", StampMilli, "Feb 4 21:00:57.012"},
+ {"StampMicro", StampMicro, "Feb 4 21:00:57.012345"},
+ {"StampNano", StampNano, "Feb 4 21:00:57.012345678"},
}
func TestFormat(t *testing.T) {
- // The numeric time represents Thu Feb 4 21:00:57 PST 2010
- time := SecondsToLocalTime(1265346057)
+ // The numeric time represents Thu Feb 4 21:00:57.012345678 PST 2010
+ time := NanosecondsToLocalTime(1233810057012345678)
for _, test := range formatTests {
result := time.Format(test.format)
if result != test.result {
@@ -166,25 +233,40 @@ func TestFormat(t *testing.T) {
}
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
+ name string
+ format string
+ value string
+ hasTZ bool // contains a time zone
+ hasWD bool // contains a weekday
+ yearSign int64 // sign of year
+ fracDigits int // number of digits of fractional second
}
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},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1, 0},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1, 0},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1, 0},
+ {"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, 0},
+ // Optional fractional seconds.
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57.0 2010", false, true, 1, 1},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57.01 PST 2010", true, true, 1, 2},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57.012 -0800 2010", true, true, 1, 3},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57.0123 PST", true, true, 1, 4},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57.01234 PST", true, true, 1, 5},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57.012345678-08:00", true, false, 1, 9},
// 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},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1, 0},
+ // Fractional seconds.
+ {"millisecond", "Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 21:00:57.012 2010", false, true, 1, 3},
+ {"microsecond", "Mon Jan _2 15:04:05.000000 2006", "Thu Feb 4 21:00:57.012345 2010", false, true, 1, 6},
+ {"nanosecond", "Mon Jan _2 15:04:05.000000000 2006", "Thu Feb 4 21:00:57.012345678 2010", false, true, 1, 9},
+ // Leading zeros in other places should not be taken as fractional seconds.
+ {"zero1", "2006.01.02.15.04.05.0", "2010.02.04.21.00.57.0", false, false, 1, 1},
+ {"zero2", "2006.01.02.15.04.05.00", "2010.02.04.21.00.57.01", false, false, 1, 2},
}
func TestParse(t *testing.T) {
@@ -199,11 +281,11 @@ func TestParse(t *testing.T) {
}
var rubyTests = []ParseTest{
- {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1, 0},
// 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},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1, 0},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1, 0},
}
// Problematic time zone format needs special tests.
@@ -238,6 +320,14 @@ func checkTime(time *Time, test *ParseTest, t *testing.T) {
if time.Second != 57 {
t.Errorf("%s: bad second: %d not %d", test.name, time.Second, 57)
}
+ // Nanoseconds must be checked against the precision of the input.
+ nanosec, err := strconv.Atoui("012345678"[:test.fracDigits] + "000000000"[:9-test.fracDigits])
+ if err != nil {
+ panic(err)
+ }
+ if time.Nanosecond != int(nanosec) {
+ t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond, nanosec)
+ }
if test.hasTZ && time.ZoneOffset != -28800 {
t.Errorf("%s: bad tz offset: %d not %d", test.name, time.ZoneOffset, -28800)
}
@@ -284,11 +374,14 @@ type ParseErrorTest struct {
}
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, "Feb 4 21:00:60 2010", "cannot parse"}, // cannot parse Feb as Mon
+ {ANSIC, "Thu Feb 4 21:00:57 @2010", "cannot 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"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59x01 2010", "cannot parse"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.xxx 2010", "cannot parse"},
+ {"Mon Jan _2 15:04:05.000 2006", "Thu Feb 4 23:00:59.-123 2010", "fractional second out of range"},
}
func TestParseErrors(t *testing.T) {
@@ -302,6 +395,66 @@ func TestParseErrors(t *testing.T) {
}
}
+func TestNoonIs12PM(t *testing.T) {
+ noon := Time{Hour: 12}
+ const expect = "12:00PM"
+ got := noon.Format("3:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+ got = noon.Format("03:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+}
+
+func TestMidnightIs12AM(t *testing.T) {
+ midnight := Time{Hour: 0}
+ expect := "12:00AM"
+ got := midnight.Format("3:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+ got = midnight.Format("03:04PM")
+ if got != expect {
+ t.Errorf("got %q; expect %q", got, expect)
+ }
+}
+
+func Test12PMIsNoon(t *testing.T) {
+ noon, err := Parse("3:04PM", "12:00PM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if noon.Hour != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour)
+ }
+ noon, err = Parse("03:04PM", "12:00PM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if noon.Hour != 12 {
+ t.Errorf("got %d; expect 12", noon.Hour)
+ }
+}
+
+func Test12AMIsMidnight(t *testing.T) {
+ midnight, err := Parse("3:04PM", "12:00AM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if midnight.Hour != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour)
+ }
+ midnight, err = Parse("03:04PM", "12:00AM")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ if midnight.Hour != 0 {
+ t.Errorf("got %d; expect 0", midnight.Hour)
+ }
+}
+
// 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) {
diff --git a/libgo/go/time/zoneinfo_plan9.go b/libgo/go/time/zoneinfo_plan9.go
new file mode 100644
index 00000000000..3c3e7c42446
--- /dev/null
+++ b/libgo/go/time/zoneinfo_plan9.go
@@ -0,0 +1,59 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse Plan 9 timezone(2) files.
+
+package time
+
+import (
+ "os"
+ "strconv"
+ "strings"
+)
+
+func parseZones(s string) (zt []zonetime) {
+ f := strings.Fields(s)
+ if len(f) < 4 {
+ return
+ }
+
+ // standard timezone offset
+ o, err := strconv.Atoi(f[1])
+ if err != nil {
+ return
+ }
+ std := &zone{name: f[0], utcoff: o, isdst: false}
+
+ // alternate timezone offset
+ o, err = strconv.Atoi(f[3])
+ if err != nil {
+ return
+ }
+ dst := &zone{name: f[2], utcoff: o, isdst: true}
+
+ // transition time pairs
+ f = f[4:]
+ for i := 0; i < len(f); i++ {
+ z := std
+ if i%2 == 0 {
+ z = dst
+ }
+ t, err := strconv.Atoi(f[i])
+ if err != nil {
+ return nil
+ }
+ t -= std.utcoff
+ zt = append(zt, zonetime{time: int32(t), zone: z})
+ }
+ return
+}
+
+func setupZone() {
+ t, err := os.Getenverror("timezone")
+ if err != nil {
+ // do nothing: use UTC
+ return
+ }
+ zones = parseZones(t)
+}
diff --git a/libgo/go/time/zoneinfo_posix.go b/libgo/go/time/zoneinfo_posix.go
new file mode 100644
index 00000000000..b49216410ff
--- /dev/null
+++ b/libgo/go/time/zoneinfo_posix.go
@@ -0,0 +1,62 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import "sync"
+
+// Parsed representation
+type zone struct {
+ utcoff int
+ isdst bool
+ name string
+}
+
+type zonetime struct {
+ time int32 // transition time, in seconds since 1970 GMT
+ zone *zone // the zone that goes into effect at that time
+ isstd, isutc bool // ignored - no idea what these mean
+}
+
+var zones []zonetime
+var onceSetupZone sync.Once
+
+// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
+func lookupTimezone(sec int64) (zone string, offset int) {
+ onceSetupZone.Do(setupZone)
+ if len(zones) == 0 {
+ return "UTC", 0
+ }
+
+ // Binary search for entry with largest time <= sec
+ tz := zones
+ for len(tz) > 1 {
+ m := len(tz) / 2
+ if sec < int64(tz[m].time) {
+ tz = tz[0:m]
+ } else {
+ tz = tz[m:]
+ }
+ }
+ z := tz[0].zone
+ return z.name, z.utcoff
+}
+
+// lookupByName returns the time offset for the
+// time zone with the given abbreviation. It only considers
+// time zones that apply to the current system.
+// For example, for a system configured as being in New York,
+// it only recognizes "EST" and "EDT".
+// For a system in San Francisco, "PST" and "PDT".
+// For a system in Sydney, "EST" and "EDT", though they have
+// different meanings than they do in New York.
+func lookupByName(name string) (off int, found bool) {
+ onceSetupZone.Do(setupZone)
+ for _, z := range zones {
+ if name == z.zone.name {
+ return z.zone.utcoff, true
+ }
+ }
+ return 0, false
+}
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index 42659ed6062..f3ea7b6fdab 100644
--- a/libgo/go/time/zoneinfo_unix.go
+++ b/libgo/go/time/zoneinfo_unix.go
@@ -12,7 +12,6 @@ package time
import (
"io/ioutil"
"os"
- "sync"
)
const (
@@ -25,7 +24,6 @@ type data struct {
error bool
}
-
func (d *data) read(n int) []byte {
if len(d.p) < n {
d.p = nil
@@ -55,7 +53,6 @@ func (d *data) byte() (n byte, ok bool) {
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++ {
@@ -66,19 +63,6 @@ func byteString(p []byte) string {
return string(p)
}
-// Parsed representation
-type zone struct {
- utcoff int
- isdst bool
- name string
-}
-
-type zonetime struct {
- time int32 // transition time, in seconds since 1970 GMT
- zone *zone // the zone that goes into effect at that time
- isstd, isutc bool // ignored - no idea what these mean
-}
-
func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
d := data{bytes, false}
@@ -201,9 +185,6 @@ func readinfofile(name string) ([]zonetime, bool) {
return parseinfo(buf)
}
-var zones []zonetime
-var onceSetupZone sync.Once
-
func setupZone() {
// consult $TZ to find the time zone to use.
// no $TZ means use the system default /etc/localtime.
@@ -230,42 +211,3 @@ func setupZone() {
// do nothing: use UTC
}
}
-
-// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
-func lookupTimezone(sec int64) (zone string, offset int) {
- onceSetupZone.Do(setupZone)
- if len(zones) == 0 {
- return "UTC", 0
- }
-
- // Binary search for entry with largest time <= sec
- tz := zones
- for len(tz) > 1 {
- m := len(tz) / 2
- if sec < int64(tz[m].time) {
- tz = tz[0:m]
- } else {
- tz = tz[m:]
- }
- }
- z := tz[0].zone
- return z.name, z.utcoff
-}
-
-// lookupByName returns the time offset for the
-// time zone with the given abbreviation. It only considers
-// time zones that apply to the current system.
-// For example, for a system configured as being in New York,
-// it only recognizes "EST" and "EDT".
-// For a system in San Francisco, "PST" and "PDT".
-// For a system in Sydney, "EST" and "EDT", though they have
-// different meanings than they do in New York.
-func lookupByName(name string) (off int, found bool) {
- onceSetupZone.Do(setupZone)
- for _, z := range zones {
- if name == z.zone.name {
- return z.zone.utcoff, true
- }
- }
- return 0, false
-}
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index c357eec62b1..fabc0060110 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -14,7 +14,7 @@ import (
// 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),
+// TODO(brainman): use GetDynamicTimeZoneInformation, whenever possible (Vista and up),
// to improve on situation described in the bug above.
type zone struct {
@@ -46,23 +46,23 @@ func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uin
return
}
-// Pre-calculte cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
+// Pre-calculate cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
func (z *zone) preCalculateAbsSec() {
if z.year != 0 {
- z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 0, ""}).Seconds()
+ z.abssec = (&Time{z.year, int(z.month), int(z.day), int(z.hour), int(z.minute), int(z.second), 0, 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.
+// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particular 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 := &Time{year, int(z.month), 1, int(z.hour), int(z.minute), int(z.second), 0, 0, 0, ""}
t = SecondsToUTC(t.Seconds())
i := int(z.dayofweek) - t.Weekday
if i < 0 {
@@ -96,7 +96,7 @@ func (z *zone) isBeforeCutoff(t *Time) bool {
}
type zoneinfo struct {
- disabled bool // daylight saving time is not used localy
+ disabled bool // daylight saving time is not used locally
offsetIfDisabled int
januaryIsStd bool // is january 1 standard time?
std, dst zone
diff --git a/libgo/go/unicode/casetables.go b/libgo/go/unicode/casetables.go
index 66440705bf2..86336b1b908 100644
--- a/libgo/go/unicode/casetables.go
+++ b/libgo/go/unicode/casetables.go
@@ -9,7 +9,6 @@
package unicode
-
var TurkishCase = _TurkishCase
var _TurkishCase = SpecialCase{
CaseRange{0x0049, 0x0049, d{0, 0x131 - 0x49, 0}},
diff --git a/libgo/go/unicode/digit.go b/libgo/go/unicode/digit.go
index 471c4dfdc59..6793fd7e5f8 100644
--- a/libgo/go/unicode/digit.go
+++ b/libgo/go/unicode/digit.go
@@ -6,7 +6,7 @@ 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
+ if rune <= MaxLatin1 {
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
index 9bbccde92a4..ae3c0ece93f 100644
--- a/libgo/go/unicode/digit_test.go
+++ b/libgo/go/unicode/digit_test.go
@@ -118,7 +118,7 @@ func TestDigit(t *testing.T) {
// Test that the special case in IsDigit agrees with the table
func TestDigitOptimization(t *testing.T) {
- for i := 0; i < 0x100; i++ {
+ for i := 0; i <= MaxLatin1; i++ {
if Is(Digit, i) != IsDigit(i) {
t.Errorf("IsDigit(U+%04X) disagrees with Is(Digit)", i)
}
diff --git a/libgo/go/unicode/graphic.go b/libgo/go/unicode/graphic.go
new file mode 100644
index 00000000000..d482aace26e
--- /dev/null
+++ b/libgo/go/unicode/graphic.go
@@ -0,0 +1,132 @@
+// 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 unicode
+
+// Bit masks for each code point under U+0100, for fast lookup.
+const (
+ pC = 1 << iota // a control character.
+ pP // a punctuation character.
+ pN // a numeral.
+ pS // a symbolic character.
+ pZ // a spacing character.
+ pLu // an upper-case letter.
+ pLl // a lower-case letter.
+ pp // a printable character according to Go's definition.
+ pg = pp | pZ // a graphical character according to the Unicode definition.
+)
+
+// GraphicRanges defines the set of graphic characters according to Unicode.
+var GraphicRanges = []*RangeTable{
+ L, M, N, P, S, Zs,
+}
+
+// PrintRanges defines the set of printable characters according to Go.
+// ASCII space, U+0020, is handled separately.
+var PrintRanges = []*RangeTable{
+ L, M, N, P, S,
+}
+
+// IsGraphic reports whether the rune is defined as a Graphic by Unicode.
+// Such characters include letters, marks, numbers, punctuation, symbols, and
+// spaces, from categories L, M, N, P, S, Zs.
+func IsGraphic(rune int) bool {
+ // We cast to uint32 to avoid the extra test for negative,
+ // and in the index we cast to uint8 to avoid the range check.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pg != 0
+ }
+ return IsOneOf(GraphicRanges, rune)
+}
+
+// IsPrint reports whether the rune is defined as printable by Go. Such
+// characters include letters, marks, numbers, punctuation, symbols, and the
+// ASCII space character, from categories L, M, N, P, S and the ASCII space
+// character. This categorization is the same as IsGraphic except that the
+// only spacing character is ASCII space, U+0020.
+func IsPrint(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pp != 0
+ }
+ return IsOneOf(PrintRanges, rune)
+}
+
+// IsOneOf reports whether the rune is a member of one of the ranges.
+// The rune is known to be above Latin-1.
+func IsOneOf(set []*RangeTable, rune int) bool {
+ for _, inside := range set {
+ if Is(inside, rune) {
+ return true
+ }
+ }
+ return false
+}
+
+// IsControl reports whether the rune is a control character.
+// The C (Other) Unicode category includes more code points
+// such as surrogates; use Is(C, rune) to test for them.
+func IsControl(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pC != 0
+ }
+ // All control characters are < Latin1Max.
+ return false
+}
+
+// IsLetter reports whether the rune is a letter (category L).
+func IsLetter(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&(pLu|pLl) != 0
+ }
+ return Is(Letter, rune)
+}
+
+// IsMark reports whether the rune is a mark character (category M).
+func IsMark(rune int) bool {
+ // There are no mark characters in Latin-1.
+ return Is(Mark, rune)
+}
+
+// IsNumber reports whether the rune is a number (category N).
+func IsNumber(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pN != 0
+ }
+ return Is(Number, rune)
+}
+
+// IsPunct reports whether the rune is a Unicode punctuation character
+// (category P).
+func IsPunct(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pP != 0
+ }
+ return Is(Punct, rune)
+}
+
+// IsSpace reports whether the rune is a space character as defined
+// by Unicode's White Space property; in the Latin-1 space
+// this is
+// '\t', '\n', '\v', '\f', '\r', ' ', U+0085 (NEL), U+00A0 (NBSP).
+// Other definitions of spacing characters are set by category
+// Z and property Pattern_White_Space.
+func IsSpace(rune int) bool {
+ // This property isn't the same as Z; special-case it.
+ if uint32(rune) <= MaxLatin1 {
+ switch rune {
+ case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0:
+ return true
+ }
+ return false
+ }
+ return Is(White_Space, rune)
+}
+
+// IsSymbol reports whether the rune is a symbolic character.
+func IsSymbol(rune int) bool {
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pS != 0
+ }
+ return Is(Symbol, rune)
+}
diff --git a/libgo/go/unicode/graphic_test.go b/libgo/go/unicode/graphic_test.go
new file mode 100644
index 00000000000..77c679f7ce0
--- /dev/null
+++ b/libgo/go/unicode/graphic_test.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package unicode_test
+
+import (
+ "testing"
+ . "unicode"
+)
+
+// Independently check that the special "Is" functions work
+// in the Latin-1 range through the property table.
+
+func TestIsControlLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsControl(i)
+ want := false
+ switch {
+ case 0x00 <= i && i <= 0x1F:
+ want = true
+ case 0x7F <= i && i <= 0x9F:
+ want = true
+ }
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsLetterLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsLetter(i)
+ want := Is(Letter, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsUpperLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsUpper(i)
+ want := Is(Upper, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsLowerLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsLower(i)
+ want := Is(Lower, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestNumberLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsNumber(i)
+ want := Is(Number, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsPrintLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsPrint(i)
+ want := IsOneOf(PrintRanges, i)
+ if i == ' ' {
+ want = true
+ }
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsGraphicLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsGraphic(i)
+ want := IsOneOf(GraphicRanges, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsPunctLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsPunct(i)
+ want := Is(Punct, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsSpaceLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsSpace(i)
+ want := Is(White_Space, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
+
+func TestIsSymbolLatin1(t *testing.T) {
+ for i := 0; i <= MaxLatin1; i++ {
+ got := IsSymbol(i)
+ want := Is(Symbol, i)
+ if got != want {
+ t.Errorf("%U incorrect: got %t; want %t", i, got, want)
+ }
+ }
+}
diff --git a/libgo/go/unicode/letter.go b/libgo/go/unicode/letter.go
index 382c6eb3f47..38a11c42bf6 100644
--- a/libgo/go/unicode/letter.go
+++ b/libgo/go/unicode/letter.go
@@ -9,15 +9,35 @@ package unicode
const (
MaxRune = 0x10FFFF // Maximum valid Unicode code point.
ReplacementChar = 0xFFFD // Represents invalid code points.
+ MaxASCII = 0x7F // maximum ASCII value.
+ MaxLatin1 = 0xFF // maximum Latin-1 value.
)
+// RangeTable defines a set of Unicode code points by listing the ranges of
+// code points within the set. The ranges are listed in two slices
+// to save space: a slice of 16-bit ranges and a slice of 32-bit ranges.
+// The two slices must be in sorted order and non-overlapping.
+// Also, R32 should contain only values >= 0x10000 (1<<16).
+type RangeTable struct {
+ R16 []Range16
+ R32 []Range32
+}
-// The representation of a range of Unicode code points. The range runs from Lo to Hi
+// Range16 represents of a range of 16-bit 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
+type Range16 struct {
+ Lo uint16
+ Hi uint16
+ Stride uint16
+}
+
+// Range32 represents of a range of Unicode code points and is used when one or
+// more of the values will not fit in 16 bits. The range runs from Lo to Hi
+// inclusive and has the specified stride. Lo and Hi must always be >= 1<<16.
+type Range32 struct {
+ Lo uint32
+ Hi uint32
+ Stride uint32
}
// CaseRange represents a range of Unicode code points for simple (one
@@ -31,8 +51,8 @@ type Range struct {
// {UpperLower, UpperLower, UpperLower}
// The constant UpperLower has an otherwise impossible delta value.
type CaseRange struct {
- Lo int
- Hi int
+ Lo uint32
+ Hi uint32
Delta d
}
@@ -60,22 +80,28 @@ 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
- }
+// is16 uses binary search to test whether rune is in the specified slice of 16-bit ranges.
+func is16(ranges []Range16, rune uint16) bool {
+ // 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
}
- return false
+ if rune < r.Lo {
+ hi = m
+ } else {
+ lo = m + 1
+ }
}
+ return false
+}
+// is32 uses binary search to test whether rune is in the specified slice of 32-bit ranges.
+func is32(ranges []Range32, rune uint32) bool {
// binary search over ranges
lo := 0
hi := len(ranges)
@@ -94,51 +120,60 @@ func Is(ranges []Range, rune int) bool {
return false
}
+// Is tests whether rune is in the specified table of ranges.
+func Is(rangeTab *RangeTable, rune int) bool {
+ // common case: rune is ASCII or Latin-1.
+ if uint32(rune) <= MaxLatin1 {
+ // Only need to check R16, since R32 is always >= 1<<16.
+ r16 := uint16(rune)
+ for _, r := range rangeTab.R16 {
+ if r16 > r.Hi {
+ continue
+ }
+ if r16 < r.Lo {
+ return false
+ }
+ return (r16-r.Lo)%r.Stride == 0
+ }
+ return false
+ }
+ r16 := rangeTab.R16
+ if len(r16) > 0 && rune <= int(r16[len(r16)-1].Hi) {
+ return is16(r16, uint16(rune))
+ }
+ r32 := rangeTab.R32
+ if len(r32) > 0 && rune >= int(r32[0].Lo) {
+ return is32(r32, uint32(rune))
+ }
+ 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'
+ // See comment in IsGraphic.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pLu != 0
}
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'
+ // See comment in IsGraphic.
+ if uint32(rune) <= MaxLatin1 {
+ return properties[uint8(rune)]&pLl != 0
}
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
+ if rune <= MaxLatin1 {
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 {
@@ -150,7 +185,7 @@ func to(_case int, rune int, caseRange []CaseRange) int {
for lo < hi {
m := lo + (hi-lo)/2
r := caseRange[m]
- if r.Lo <= rune && rune <= r.Hi {
+ if int(r.Lo) <= rune && rune <= int(r.Hi) {
delta := int(r.Delta[_case])
if delta > MaxRune {
// In an Upper-Lower sequence, which always starts with
@@ -163,11 +198,11 @@ func to(_case int, rune int, caseRange []CaseRange) int {
// 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 int(r.Lo) + ((rune-int(r.Lo))&^1 | _case&1)
}
return rune + delta
}
- if rune < r.Lo {
+ if rune < int(r.Lo) {
hi = m
} else {
lo = m + 1
@@ -183,7 +218,7 @@ func To(_case int, rune int) int {
// ToUpper maps the rune to upper case.
func ToUpper(rune int) int {
- if rune < 0x80 { // quick ASCII check
+ if rune <= MaxASCII {
if 'a' <= rune && rune <= 'z' {
rune -= 'a' - 'A'
}
@@ -194,7 +229,7 @@ func ToUpper(rune int) int {
// ToLower maps the rune to lower case.
func ToLower(rune int) int {
- if rune < 0x80 { // quick ASCII check
+ if rune <= MaxASCII {
if 'A' <= rune && rune <= 'Z' {
rune += 'a' - 'A'
}
@@ -205,7 +240,7 @@ func ToLower(rune int) int {
// ToTitle maps the rune to title case.
func ToTitle(rune int) int {
- if rune < 0x80 { // quick ASCII check
+ if rune <= MaxASCII {
if 'a' <= rune && rune <= 'z' { // title case is upper case for ASCII
rune -= 'a' - 'A'
}
@@ -240,3 +275,52 @@ func (special SpecialCase) ToLower(rune int) int {
}
return r
}
+
+// caseOrbit is defined in tables.go as []foldPair. Right now all the
+// entries fit in uint16, so use uint16. If that changes, compilation
+// will fail (the constants in the composite literal will not fit in uint16)
+// and the types here can change to uint32.
+type foldPair struct {
+ From uint16
+ To uint16
+}
+
+// SimpleFold iterates over Unicode code points equivalent under
+// the Unicode-defined simple case folding. Among the code points
+// equivalent to rune (including rune itself), SimpleFold returns the
+// smallest r >= rune if one exists, or else the smallest r >= 0.
+//
+// For example:
+// SimpleFold('A') = 'a'
+// SimpleFold('a') = 'A'
+//
+// SimpleFold('K') = 'k'
+// SimpleFold('k') = '\u212A' (Kelvin symbol, K)
+// SimpleFold('\u212A') = 'K'
+//
+// SimpleFold('1') = '1'
+//
+func SimpleFold(rune int) int {
+ // Consult caseOrbit table for special cases.
+ lo := 0
+ hi := len(caseOrbit)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ if int(caseOrbit[m].From) < rune {
+ lo = m + 1
+ } else {
+ hi = m
+ }
+ }
+ if lo < len(caseOrbit) && int(caseOrbit[lo].From) == rune {
+ return int(caseOrbit[lo].To)
+ }
+
+ // No folding specified. This is a one- or two-element
+ // equivalence class containing rune and ToLower(rune)
+ // and ToUpper(rune) if they are different from rune.
+ if l := ToLower(rune); l != rune {
+ return l
+ }
+ return ToUpper(rune)
+}
diff --git a/libgo/go/unicode/letter_test.go b/libgo/go/unicode/letter_test.go
index 432ffb67130..8d2665a44fc 100644
--- a/libgo/go/unicode/letter_test.go
+++ b/libgo/go/unicode/letter_test.go
@@ -212,6 +212,10 @@ var caseTest = []caseT{
{UpperCase, 0x10450, 0x10450},
{LowerCase, 0x10450, 0x10450},
{TitleCase, 0x10450, 0x10450},
+
+ // Non-letters with case.
+ {LowerCase, 0x2161, 0x2171},
+ {UpperCase, 0x0345, 0x0399},
}
func TestIsLetter(t *testing.T) {
@@ -323,7 +327,7 @@ func TestIsSpace(t *testing.T) {
// 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++ {
+ for i := 0; i <= MaxLatin1; i++ {
if Is(Letter, i) != IsLetter(i) {
t.Errorf("IsLetter(U+%04X) disagrees with Is(Letter)", i)
}
@@ -376,3 +380,49 @@ func TestTurkishCase(t *testing.T) {
}
}
}
+
+var simpleFoldTests = []string{
+ // SimpleFold could order its returned slices in any order it wants,
+ // but we know it orders them in increasing order starting at in
+ // and looping around from MaxRune to 0.
+
+ // Easy cases.
+ "Aa",
+ "aA",
+ "δΔ",
+ "Δδ",
+
+ // ASCII special cases.
+ "KkK",
+ "kKK",
+ "KKk",
+ "Ssſ",
+ "sſS",
+ "ſSs",
+
+ // Non-ASCII special cases.
+ "ρϱΡ",
+ "ϱΡρ",
+ "Ρρϱ",
+ "ͅΙιι",
+ "Ιιιͅ",
+ "ιιͅΙ",
+ "ιͅΙι",
+
+ // Extra special cases: has lower/upper but no case fold.
+ "İ",
+ "ı",
+}
+
+func TestSimpleFold(t *testing.T) {
+ for _, tt := range simpleFoldTests {
+ cycle := []int(tt)
+ rune := cycle[len(cycle)-1]
+ for _, out := range cycle {
+ if r := SimpleFold(rune); r != out {
+ t.Errorf("SimpleFold(%#U) = %#U, want %#U", rune, r, out)
+ }
+ rune = out
+ }
+ }
+}
diff --git a/libgo/go/unicode/script_test.go b/libgo/go/unicode/script_test.go
index ff452b75ced..b37ad183615 100644
--- a/libgo/go/unicode/script_test.go
+++ b/libgo/go/unicode/script_test.go
@@ -149,7 +149,14 @@ var inCategoryTest = []T{
{0x2028, "Zl"},
{0x2029, "Zp"},
{0x202f, "Zs"},
- {0x04aa, "letter"},
+ // Unifieds.
+ {0x04aa, "L"},
+ {0x0009, "C"},
+ {0x1712, "M"},
+ {0x0031, "N"},
+ {0x00bb, "P"},
+ {0x00a2, "S"},
+ {0x00a0, "Z"},
}
var inPropTest = []T{
@@ -197,13 +204,13 @@ func TestScripts(t *testing.T) {
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)
+ t.Errorf("IsScript(%U, %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)
+ t.Errorf("IsScript(%U, %s) = true, want false", test.rune, test.script)
}
}
for k := range notTested {
@@ -221,7 +228,7 @@ func TestCategories(t *testing.T) {
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)
+ t.Errorf("IsCategory(%U, %s) = false, want true", test.rune, test.script)
}
notTested[test.script] = false, false
}
@@ -240,7 +247,7 @@ func TestProperties(t *testing.T) {
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)
+ t.Errorf("IsCategory(%U, %s) = false, want true", test.rune, test.script)
}
notTested[test.script] = false, false
}
diff --git a/libgo/go/unicode/tables.go b/libgo/go/unicode/tables.go
index 89fd99411bc..88b5c0fbaaa 100644
--- a/libgo/go/unicode/tables.go
+++ b/libgo/go/unicode/tables.go
@@ -1,5 +1,5 @@
// Generated by running
-// maketables --tables=all --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt
+// maketables --tables=all --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.0.0/ucd/CaseFolding.txt
// DO NOT EDIT
package unicode
@@ -8,2009 +8,2747 @@ package unicode
const Version = "6.0.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, 0x209c, 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, 0x0527, 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, 0xa66d, 2},
- {0xa681, 0xa697, 2},
- {0xa723, 0xa72f, 2},
- {0xa730, 0xa731, 1},
- {0xa733, 0xa771, 2},
- {0xa772, 0xa778, 1},
- {0xa77a, 0xa77c, 2},
- {0xa77f, 0xa787, 2},
- {0xa78c, 0xa78e, 2},
- {0xa791, 0xa7a1, 16},
- {0xa7a3, 0xa7a9, 2},
- {0xa7fa, 0xfb00, 21254},
- {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},
- {0x20dd, 0x20e0, 1},
- {0x20e2, 0x20e4, 1},
- {0xa670, 0xa672, 1},
-}
-
-var _Mc = []Range{
- {0x0903, 0x093b, 56},
- {0x093e, 0x0940, 1},
- {0x0949, 0x094c, 1},
- {0x094e, 0x094f, 1},
- {0x0982, 0x0983, 1},
- {0x09be, 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, 0x1be7, 61},
- {0x1bea, 0x1bec, 1},
- {0x1bee, 0x1bf2, 4},
- {0x1bf3, 0x1c24, 49},
- {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, 0x11000, 25620},
- {0x11002, 0x11082, 128},
- {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, 0x065f, 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},
- {0x0859, 0x085b, 1},
- {0x0900, 0x0902, 1},
- {0x093a, 0x093c, 2},
- {0x0941, 0x0948, 1},
- {0x094d, 0x0951, 4},
- {0x0952, 0x0957, 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},
- {0x0f8d, 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, 0x135d, 704},
- {0x135e, 0x135f, 1},
- {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},
- {0x1be6, 0x1be8, 2},
- {0x1be9, 0x1bed, 4},
- {0x1bef, 0x1bf1, 1},
- {0x1c2c, 0x1c33, 1},
- {0x1c36, 0x1c37, 1},
- {0x1cd0, 0x1cd2, 1},
- {0x1cd4, 0x1ce0, 1},
- {0x1ce2, 0x1ce8, 1},
- {0x1ced, 0x1dc0, 211},
- {0x1dc1, 0x1de6, 1},
- {0x1dfc, 0x1dff, 1},
- {0x20d0, 0x20dc, 1},
- {0x20e1, 0x20e5, 4},
- {0x20e6, 0x20f0, 1},
- {0x2cef, 0x2cf1, 1},
- {0x2d7f, 0x2de0, 97},
- {0x2de1, 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, 0x11001, 1474},
- {0x11038, 0x11046, 1},
- {0x11080, 0x11081, 1},
- {0x110b3, 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, 0x0527, 1},
- {0x0531, 0x0556, 1},
- {0x0559, 0x0561, 8},
- {0x0562, 0x0587, 1},
- {0x05d0, 0x05ea, 1},
- {0x05f0, 0x05f2, 1},
- {0x0620, 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, 0x0840, 24},
- {0x0841, 0x0858, 1},
- {0x0904, 0x0939, 1},
- {0x093d, 0x0950, 19},
- {0x0958, 0x0961, 1},
- {0x0971, 0x0977, 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},
- {0x0cf1, 0x0cf2, 1},
- {0x0d05, 0x0d0c, 1},
- {0x0d0e, 0x0d10, 1},
- {0x0d12, 0x0d3a, 1},
- {0x0d3d, 0x0d4e, 17},
- {0x0d60, 0x0d61, 1},
- {0x0d7a, 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, 0x0f8c, 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},
- {0x1bc0, 0x1be5, 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, 0x209c, 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, 0x31ba, 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, 0xa66e, 1},
- {0xa67f, 0xa697, 1},
- {0xa6a0, 0xa6e5, 1},
- {0xa717, 0xa71f, 1},
- {0xa722, 0xa788, 1},
- {0xa78b, 0xa78e, 1},
- {0xa790, 0xa791, 1},
- {0xa7a0, 0xa7a9, 1},
- {0xa7fa, 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},
- {0xab01, 0xab06, 1},
- {0xab09, 0xab0e, 1},
- {0xab11, 0xab16, 1},
- {0xab20, 0xab26, 1},
- {0xab28, 0xab2e, 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},
- {0x11003, 0x11037, 1},
- {0x11083, 0x110af, 1},
- {0x12000, 0x1236e, 1},
- {0x13000, 0x1342e, 1},
- {0x16800, 0x16a38, 1},
- {0x1b000, 0x1b001, 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},
- {0x2b740, 0x2b81d, 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},
- {0x085e, 0x0964, 262},
- {0x0965, 0x0970, 11},
- {0x0df4, 0x0e4f, 91},
- {0x0e5a, 0x0e5b, 1},
- {0x0f04, 0x0f12, 1},
- {0x0f85, 0x0fd0, 75},
- {0x0fd1, 0x0fd4, 1},
- {0x0fd9, 0x0fda, 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},
- {0x1a1e, 0x1a1f, 1},
- {0x1aa0, 0x1aa6, 1},
- {0x1aa8, 0x1aad, 1},
- {0x1b5a, 0x1b60, 1},
- {0x1bfc, 0x1bff, 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},
- {0x2d70, 0x2e00, 144},
- {0x2e01, 0x2e06, 5},
- {0x2e07, 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},
- {0x11047, 0x1104d, 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, 0x19d9, 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},
- {0x11066, 0x1106f, 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},
- {0x0b72, 0x0b77, 1},
- {0x0bf0, 0x0bf2, 1},
- {0x0c78, 0x0c7e, 1},
- {0x0d70, 0x0d75, 1},
- {0x0f2a, 0x0f33, 1},
- {0x1369, 0x137c, 1},
- {0x17f0, 0x17f9, 1},
- {0x19da, 0x2070, 1686},
- {0x2074, 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},
- {0x11052, 0x11065, 1},
- {0x1d360, 0x1d371, 1},
- {0x1f100, 0x1f10a, 1},
-}
-
-var _So = []Range{
- {0x00a6, 0x00a7, 1},
- {0x00a9, 0x00ae, 5},
- {0x00b0, 0x00b6, 6},
- {0x0482, 0x060e, 396},
- {0x060f, 0x06de, 207},
- {0x06e9, 0x06fd, 20},
- {0x06fe, 0x07f6, 248},
- {0x09fa, 0x0b70, 374},
- {0x0bf3, 0x0bf8, 1},
- {0x0bfa, 0x0c7f, 133},
- {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, 0x19de, 158},
- {0x19df, 0x19ff, 1},
- {0x1b61, 0x1b6a, 1},
- {0x1b74, 0x1b7c, 1},
- {0x2100, 0x2101, 1},
- {0x2103, 0x2106, 1},
- {0x2108, 0x2109, 1},
- {0x2114, 0x2116, 2},
- {0x2117, 0x211e, 7},
- {0x211f, 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, 0x23f3, 1},
- {0x2400, 0x2426, 1},
- {0x2440, 0x244a, 1},
- {0x249c, 0x24e9, 1},
- {0x2500, 0x25b6, 1},
- {0x25b8, 0x25c0, 1},
- {0x25c2, 0x25f7, 1},
- {0x2600, 0x266e, 1},
- {0x2670, 0x26ff, 1},
- {0x2701, 0x2767, 1},
- {0x2794, 0x27bf, 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},
- {0x1f0a0, 0x1f0ae, 1},
- {0x1f0b1, 0x1f0be, 1},
- {0x1f0c1, 0x1f0cf, 1},
- {0x1f0d1, 0x1f0df, 1},
- {0x1f110, 0x1f12e, 1},
- {0x1f130, 0x1f169, 1},
- {0x1f170, 0x1f19a, 1},
- {0x1f1e6, 0x1f202, 1},
- {0x1f210, 0x1f23a, 1},
- {0x1f240, 0x1f248, 1},
- {0x1f250, 0x1f251, 1},
- {0x1f300, 0x1f320, 1},
- {0x1f330, 0x1f335, 1},
- {0x1f337, 0x1f37c, 1},
- {0x1f380, 0x1f393, 1},
- {0x1f3a0, 0x1f3c4, 1},
- {0x1f3c6, 0x1f3ca, 1},
- {0x1f3e0, 0x1f3f0, 1},
- {0x1f400, 0x1f43e, 1},
- {0x1f440, 0x1f442, 2},
- {0x1f443, 0x1f4f7, 1},
- {0x1f4f9, 0x1f4fc, 1},
- {0x1f500, 0x1f53d, 1},
- {0x1f550, 0x1f567, 1},
- {0x1f5fb, 0x1f5ff, 1},
- {0x1f601, 0x1f610, 1},
- {0x1f612, 0x1f614, 1},
- {0x1f616, 0x1f61c, 2},
- {0x1f61d, 0x1f61e, 1},
- {0x1f620, 0x1f625, 1},
- {0x1f628, 0x1f62b, 1},
- {0x1f62d, 0x1f630, 3},
- {0x1f631, 0x1f633, 1},
- {0x1f635, 0x1f640, 1},
- {0x1f645, 0x1f64f, 1},
- {0x1f680, 0x1f6c5, 1},
- {0x1f700, 0x1f773, 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},
- {0x2118, 0x2140, 40},
- {0x2141, 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, 0x27ce, 2},
- {0x27cf, 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},
- {0xfbb2, 0xfbc1, 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, 0x20b9, 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, 0x0526, 2},
- {0x0531, 0x0556, 1},
- {0x10a0, 0x10c5, 1},
- {0x1e00, 0x1e94, 2},
- {0x1e9e, 0x1efe, 2},
- {0x1f08, 0x1f0f, 1},
- {0x1f18, 0x1f1d, 1},
- {0x1f28, 0x1f2f, 1},
- {0x1f38, 0x1f3f, 1},
- {0x1f48, 0x1f4d, 1},
- {0x1f59, 0x1f5f, 2},
- {0x1f68, 0x1f6f, 1},
- {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, 0xa66c, 2},
- {0xa680, 0xa696, 2},
- {0xa722, 0xa72e, 2},
- {0xa732, 0xa76e, 2},
- {0xa779, 0xa77d, 2},
- {0xa77e, 0xa786, 2},
- {0xa78b, 0xa78d, 2},
- {0xa790, 0xa7a0, 16},
- {0xa7a2, 0xa7a8, 2},
- {0xff21, 0xff3a, 1},
- {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},
- {0x0620, 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},
- {0x0840, 0x0858, 1},
- {0x0904, 0x0939, 1},
- {0x093d, 0x0950, 19},
- {0x0958, 0x0961, 1},
- {0x0972, 0x0977, 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},
- {0x0cf1, 0x0cf2, 1},
- {0x0d05, 0x0d0c, 1},
- {0x0d0e, 0x0d10, 1},
- {0x0d12, 0x0d3a, 1},
- {0x0d3d, 0x0d4e, 17},
- {0x0d60, 0x0d61, 1},
- {0x0d7a, 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, 0x0f8c, 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},
- {0x1bc0, 0x1be5, 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, 0x31ba, 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},
- {0xab01, 0xab06, 1},
- {0xab09, 0xab0e, 1},
- {0xab11, 0xab16, 1},
- {0xab20, 0xab26, 1},
- {0xab28, 0xab2e, 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},
- {0x11003, 0x11037, 1},
- {0x11083, 0x110af, 1},
- {0x12000, 0x1236e, 1},
- {0x13000, 0x1342e, 1},
- {0x16800, 0x16a38, 1},
- {0x1b000, 0x1b001, 1},
- {0x20000, 0x2a6d6, 1},
- {0x2a700, 0x2b734, 1},
- {0x2b740, 0x2b81d, 1},
- {0x2f800, 0x2fa1d, 1},
+var Categories = map[string]*RangeTable{
+ "Lm": Lm,
+ "Ll": Ll,
+ "C": C,
+ "M": M,
+ "L": L,
+ "N": N,
+ "P": P,
+ "S": S,
+ "Z": Z,
+ "Me": Me,
+ "Mc": Mc,
+ "Mn": Mn,
+ "Zl": Zl,
+ "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 = &RangeTable{
+ R16: []Range16{
+ {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, 0x209c, 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 = &RangeTable{
+ R16: []Range16{
+ {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, 0x0527, 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, 0xa66d, 2},
+ {0xa681, 0xa697, 2},
+ {0xa723, 0xa72f, 2},
+ {0xa730, 0xa731, 1},
+ {0xa733, 0xa771, 2},
+ {0xa772, 0xa778, 1},
+ {0xa77a, 0xa77c, 2},
+ {0xa77f, 0xa787, 2},
+ {0xa78c, 0xa78e, 2},
+ {0xa791, 0xa7a1, 16},
+ {0xa7a3, 0xa7a9, 2},
+ {0xa7fa, 0xfb00, 21254},
+ {0xfb01, 0xfb06, 1},
+ {0xfb13, 0xfb17, 1},
+ {0xff41, 0xff5a, 1},
+ },
+ R32: []Range32{
+ {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 _C = &RangeTable{
+ R16: []Range16{
+ {0x0001, 0x001f, 1},
+ {0x007f, 0x009f, 1},
+ {0x00ad, 0x0600, 1363},
+ {0x0601, 0x0603, 1},
+ {0x06dd, 0x070f, 50},
+ {0x17b4, 0x17b5, 1},
+ {0x200b, 0x200f, 1},
+ {0x202a, 0x202e, 1},
+ {0x2060, 0x2064, 1},
+ {0x206a, 0x206f, 1},
+ {0xd800, 0xf8ff, 1},
+ {0xfeff, 0xfff9, 250},
+ {0xfffa, 0xfffb, 1},
+ },
+ R32: []Range32{
+ {0x110bd, 0x1d173, 49334},
+ {0x1d174, 0x1d17a, 1},
+ {0xe0001, 0xe0020, 31},
+ {0xe0021, 0xe007f, 1},
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
+ },
+}
+
+var _M = &RangeTable{
+ R16: []Range16{
+ {0x0300, 0x036f, 1},
+ {0x0483, 0x0489, 1},
+ {0x0591, 0x05bd, 1},
+ {0x05bf, 0x05c1, 2},
+ {0x05c2, 0x05c4, 2},
+ {0x05c5, 0x05c7, 2},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x065f, 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},
+ {0x0859, 0x085b, 1},
+ {0x0900, 0x0903, 1},
+ {0x093a, 0x093c, 1},
+ {0x093e, 0x094f, 1},
+ {0x0951, 0x0957, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x0983, 1},
+ {0x09bc, 0x09be, 2},
+ {0x09bf, 0x09c4, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cd, 1},
+ {0x09d7, 0x09e2, 11},
+ {0x09e3, 0x0a01, 30},
+ {0x0a02, 0x0a03, 1},
+ {0x0a3c, 0x0a3e, 2},
+ {0x0a3f, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4d, 1},
+ {0x0a51, 0x0a70, 31},
+ {0x0a71, 0x0a75, 4},
+ {0x0a81, 0x0a83, 1},
+ {0x0abc, 0x0abe, 2},
+ {0x0abf, 0x0ac5, 1},
+ {0x0ac7, 0x0ac9, 1},
+ {0x0acb, 0x0acd, 1},
+ {0x0ae2, 0x0ae3, 1},
+ {0x0b01, 0x0b03, 1},
+ {0x0b3c, 0x0b3e, 2},
+ {0x0b3f, 0x0b44, 1},
+ {0x0b47, 0x0b48, 1},
+ {0x0b4b, 0x0b4d, 1},
+ {0x0b56, 0x0b57, 1},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0bbe, 60},
+ {0x0bbf, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcd, 1},
+ {0x0bd7, 0x0c01, 42},
+ {0x0c02, 0x0c03, 1},
+ {0x0c3e, 0x0c44, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4d, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbc, 0x0cbe, 2},
+ {0x0cbf, 0x0cc4, 1},
+ {0x0cc6, 0x0cc8, 1},
+ {0x0cca, 0x0ccd, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0ce2, 0x0ce3, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4d, 1},
+ {0x0d57, 0x0d62, 11},
+ {0x0d63, 0x0d82, 31},
+ {0x0d83, 0x0dca, 71},
+ {0x0dcf, 0x0dd4, 1},
+ {0x0dd6, 0x0dd8, 2},
+ {0x0dd9, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0e31, 0x0e34, 3},
+ {0x0e35, 0x0e3a, 1},
+ {0x0e47, 0x0e4e, 1},
+ {0x0eb1, 0x0eb4, 3},
+ {0x0eb5, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ec8, 0x0ecd, 1},
+ {0x0f18, 0x0f19, 1},
+ {0x0f35, 0x0f39, 2},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f71, 0x0f84, 1},
+ {0x0f86, 0x0f87, 1},
+ {0x0f8d, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fc6, 0x102b, 101},
+ {0x102c, 0x103e, 1},
+ {0x1056, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1062, 0x1064, 1},
+ {0x1067, 0x106d, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x108d, 1},
+ {0x108f, 0x109a, 11},
+ {0x109b, 0x109d, 1},
+ {0x135d, 0x135f, 1},
+ {0x1712, 0x1714, 1},
+ {0x1732, 0x1734, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b6, 0x17d3, 1},
+ {0x17dd, 0x180b, 46},
+ {0x180c, 0x180d, 1},
+ {0x18a9, 0x1920, 119},
+ {0x1921, 0x192b, 1},
+ {0x1930, 0x193b, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a17, 0x1a1b, 1},
+ {0x1a55, 0x1a5e, 1},
+ {0x1a60, 0x1a7c, 1},
+ {0x1a7f, 0x1b00, 129},
+ {0x1b01, 0x1b04, 1},
+ {0x1b34, 0x1b44, 1},
+ {0x1b6b, 0x1b73, 1},
+ {0x1b80, 0x1b82, 1},
+ {0x1ba1, 0x1baa, 1},
+ {0x1be6, 0x1bf3, 1},
+ {0x1c24, 0x1c37, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce8, 1},
+ {0x1ced, 0x1cf2, 5},
+ {0x1dc0, 0x1de6, 1},
+ {0x1dfc, 0x1dff, 1},
+ {0x20d0, 0x20f0, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2d7f, 0x2de0, 97},
+ {0x2de1, 0x2dff, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309a, 1},
+ {0xa66f, 0xa672, 1},
+ {0xa67c, 0xa67d, 1},
+ {0xa6f0, 0xa6f1, 1},
+ {0xa802, 0xa806, 4},
+ {0xa80b, 0xa823, 24},
+ {0xa824, 0xa827, 1},
+ {0xa880, 0xa881, 1},
+ {0xa8b4, 0xa8c4, 1},
+ {0xa8e0, 0xa8f1, 1},
+ {0xa926, 0xa92d, 1},
+ {0xa947, 0xa953, 1},
+ {0xa980, 0xa983, 1},
+ {0xa9b3, 0xa9c0, 1},
+ {0xaa29, 0xaa36, 1},
+ {0xaa43, 0xaa4c, 9},
+ {0xaa4d, 0xaa7b, 46},
+ {0xaab0, 0xaab2, 2},
+ {0xaab3, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabf, 1},
+ {0xaac1, 0xabe3, 290},
+ {0xabe4, 0xabea, 1},
+ {0xabec, 0xabed, 1},
+ {0xfb1e, 0xfe00, 738},
+ {0xfe01, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ },
+ R32: []Range32{
+ {0x101fd, 0x10a01, 2052},
+ {0x10a02, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x11000, 1473},
+ {0x11001, 0x11002, 1},
+ {0x11038, 0x11046, 1},
+ {0x11080, 0x11082, 1},
+ {0x110b0, 0x110ba, 1},
+ {0x1d165, 0x1d169, 1},
+ {0x1d16d, 0x1d172, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0x1d242, 0x1d244, 1},
+ {0xe0100, 0xe01ef, 1},
+ },
+}
+
+var _L = &RangeTable{
+ R16: []Range16{
+ {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, 0x0527, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0561, 8},
+ {0x0562, 0x0587, 1},
+ {0x05d0, 0x05ea, 1},
+ {0x05f0, 0x05f2, 1},
+ {0x0620, 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, 0x0840, 24},
+ {0x0841, 0x0858, 1},
+ {0x0904, 0x0939, 1},
+ {0x093d, 0x0950, 19},
+ {0x0958, 0x0961, 1},
+ {0x0971, 0x0977, 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},
+ {0x0cf1, 0x0cf2, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d3a, 1},
+ {0x0d3d, 0x0d4e, 17},
+ {0x0d60, 0x0d61, 1},
+ {0x0d7a, 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, 0x0f8c, 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},
+ {0x1bc0, 0x1be5, 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, 0x209c, 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, 0x31ba, 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, 0xa66e, 1},
+ {0xa67f, 0xa697, 1},
+ {0xa6a0, 0xa6e5, 1},
+ {0xa717, 0xa71f, 1},
+ {0xa722, 0xa788, 1},
+ {0xa78b, 0xa78e, 1},
+ {0xa790, 0xa791, 1},
+ {0xa7a0, 0xa7a9, 1},
+ {0xa7fa, 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},
+ {0xab01, 0xab06, 1},
+ {0xab09, 0xab0e, 1},
+ {0xab11, 0xab16, 1},
+ {0xab20, 0xab26, 1},
+ {0xab28, 0xab2e, 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},
+ },
+ R32: []Range32{
+ {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},
+ {0x11003, 0x11037, 1},
+ {0x11083, 0x110af, 1},
+ {0x12000, 0x1236e, 1},
+ {0x13000, 0x1342e, 1},
+ {0x16800, 0x16a38, 1},
+ {0x1b000, 0x1b001, 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},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
+ },
+}
+
+var _N = &RangeTable{
+ R16: []Range16{
+ {0x0030, 0x0039, 1},
+ {0x00b2, 0x00b3, 1},
+ {0x00b9, 0x00bc, 3},
+ {0x00bd, 0x00be, 1},
+ {0x0660, 0x0669, 1},
+ {0x06f0, 0x06f9, 1},
+ {0x07c0, 0x07c9, 1},
+ {0x0966, 0x096f, 1},
+ {0x09e6, 0x09ef, 1},
+ {0x09f4, 0x09f9, 1},
+ {0x0a66, 0x0a6f, 1},
+ {0x0ae6, 0x0aef, 1},
+ {0x0b66, 0x0b6f, 1},
+ {0x0b72, 0x0b77, 1},
+ {0x0be6, 0x0bf2, 1},
+ {0x0c66, 0x0c6f, 1},
+ {0x0c78, 0x0c7e, 1},
+ {0x0ce6, 0x0cef, 1},
+ {0x0d66, 0x0d75, 1},
+ {0x0e50, 0x0e59, 1},
+ {0x0ed0, 0x0ed9, 1},
+ {0x0f20, 0x0f33, 1},
+ {0x1040, 0x1049, 1},
+ {0x1090, 0x1099, 1},
+ {0x1369, 0x137c, 1},
+ {0x16ee, 0x16f0, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x17f0, 0x17f9, 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},
+ {0x2070, 0x2074, 4},
+ {0x2075, 0x2079, 1},
+ {0x2080, 0x2089, 1},
+ {0x2150, 0x2182, 1},
+ {0x2185, 0x2189, 1},
+ {0x2460, 0x249b, 1},
+ {0x24ea, 0x24ff, 1},
+ {0x2776, 0x2793, 1},
+ {0x2cfd, 0x3007, 778},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0x3192, 0x3195, 1},
+ {0x3220, 0x3229, 1},
+ {0x3251, 0x325f, 1},
+ {0x3280, 0x3289, 1},
+ {0x32b1, 0x32bf, 1},
+ {0xa620, 0xa629, 1},
+ {0xa6e6, 0xa6ef, 1},
+ {0xa830, 0xa835, 1},
+ {0xa8d0, 0xa8d9, 1},
+ {0xa900, 0xa909, 1},
+ {0xa9d0, 0xa9d9, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xabf0, 0xabf9, 1},
+ {0xff10, 0xff19, 1},
+ },
+ R32: []Range32{
+ {0x10107, 0x10133, 1},
+ {0x10140, 0x10178, 1},
+ {0x1018a, 0x10320, 406},
+ {0x10321, 0x10323, 1},
+ {0x10341, 0x1034a, 9},
+ {0x103d1, 0x103d5, 1},
+ {0x104a0, 0x104a9, 1},
+ {0x10858, 0x1085f, 1},
+ {0x10916, 0x1091b, 1},
+ {0x10a40, 0x10a47, 1},
+ {0x10a7d, 0x10a7e, 1},
+ {0x10b58, 0x10b5f, 1},
+ {0x10b78, 0x10b7f, 1},
+ {0x10e60, 0x10e7e, 1},
+ {0x11052, 0x1106f, 1},
+ {0x12400, 0x12462, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ {0x1f100, 0x1f10a, 1},
+ },
+}
+
+var _P = &RangeTable{
+ R16: []Range16{
+ {0x0021, 0x0023, 1},
+ {0x0025, 0x002a, 1},
+ {0x002c, 0x002f, 1},
+ {0x003a, 0x003b, 1},
+ {0x003f, 0x0040, 1},
+ {0x005b, 0x005d, 1},
+ {0x005f, 0x007b, 28},
+ {0x007d, 0x00a1, 36},
+ {0x00ab, 0x00b7, 12},
+ {0x00bb, 0x00bf, 4},
+ {0x037e, 0x0387, 9},
+ {0x055a, 0x055f, 1},
+ {0x0589, 0x058a, 1},
+ {0x05be, 0x05c0, 2},
+ {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},
+ {0x085e, 0x0964, 262},
+ {0x0965, 0x0970, 11},
+ {0x0df4, 0x0e4f, 91},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f04, 0x0f12, 1},
+ {0x0f3a, 0x0f3d, 1},
+ {0x0f85, 0x0fd0, 75},
+ {0x0fd1, 0x0fd4, 1},
+ {0x0fd9, 0x0fda, 1},
+ {0x104a, 0x104f, 1},
+ {0x10fb, 0x1361, 614},
+ {0x1362, 0x1368, 1},
+ {0x1400, 0x166d, 621},
+ {0x166e, 0x169b, 45},
+ {0x169c, 0x16eb, 79},
+ {0x16ec, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17d8, 0x17da, 1},
+ {0x1800, 0x180a, 1},
+ {0x1944, 0x1945, 1},
+ {0x1a1e, 0x1a1f, 1},
+ {0x1aa0, 0x1aa6, 1},
+ {0x1aa8, 0x1aad, 1},
+ {0x1b5a, 0x1b60, 1},
+ {0x1bfc, 0x1bff, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x1cd3, 0x2010, 829},
+ {0x2011, 0x2027, 1},
+ {0x2030, 0x2043, 1},
+ {0x2045, 0x2051, 1},
+ {0x2053, 0x205e, 1},
+ {0x207d, 0x207e, 1},
+ {0x208d, 0x208e, 1},
+ {0x2329, 0x232a, 1},
+ {0x2768, 0x2775, 1},
+ {0x27c5, 0x27c6, 1},
+ {0x27e6, 0x27ef, 1},
+ {0x2983, 0x2998, 1},
+ {0x29d8, 0x29db, 1},
+ {0x29fc, 0x29fd, 1},
+ {0x2cf9, 0x2cfc, 1},
+ {0x2cfe, 0x2cff, 1},
+ {0x2d70, 0x2e00, 144},
+ {0x2e01, 0x2e2e, 1},
+ {0x2e30, 0x2e31, 1},
+ {0x3001, 0x3003, 1},
+ {0x3008, 0x3011, 1},
+ {0x3014, 0x301f, 1},
+ {0x3030, 0x303d, 13},
+ {0x30a0, 0x30fb, 91},
+ {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, 0xfd3e, 20819},
+ {0xfd3f, 0xfe10, 209},
+ {0xfe11, 0xfe19, 1},
+ {0xfe30, 0xfe52, 1},
+ {0xfe54, 0xfe61, 1},
+ {0xfe63, 0xfe68, 5},
+ {0xfe6a, 0xfe6b, 1},
+ {0xff01, 0xff03, 1},
+ {0xff05, 0xff0a, 1},
+ {0xff0c, 0xff0f, 1},
+ {0xff1a, 0xff1b, 1},
+ {0xff1f, 0xff20, 1},
+ {0xff3b, 0xff3d, 1},
+ {0xff3f, 0xff5b, 28},
+ {0xff5d, 0xff5f, 2},
+ {0xff60, 0xff65, 1},
+ },
+ R32: []Range32{
+ {0x10100, 0x10101, 1},
+ {0x1039f, 0x103d0, 49},
+ {0x10857, 0x1091f, 200},
+ {0x1093f, 0x10a50, 273},
+ {0x10a51, 0x10a58, 1},
+ {0x10a7f, 0x10b39, 186},
+ {0x10b3a, 0x10b3f, 1},
+ {0x11047, 0x1104d, 1},
+ {0x110bb, 0x110bc, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _S = &RangeTable{
+ R16: []Range16{
+ {0x0024, 0x002b, 7},
+ {0x003c, 0x003e, 1},
+ {0x005e, 0x0060, 2},
+ {0x007c, 0x007e, 2},
+ {0x00a2, 0x00a9, 1},
+ {0x00ac, 0x00ae, 2},
+ {0x00af, 0x00b1, 1},
+ {0x00b4, 0x00b8, 2},
+ {0x00d7, 0x00f7, 32},
+ {0x02c2, 0x02c5, 1},
+ {0x02d2, 0x02df, 1},
+ {0x02e5, 0x02eb, 1},
+ {0x02ed, 0x02ef, 2},
+ {0x02f0, 0x02ff, 1},
+ {0x0375, 0x0384, 15},
+ {0x0385, 0x03f6, 113},
+ {0x0482, 0x0606, 388},
+ {0x0607, 0x0608, 1},
+ {0x060b, 0x060e, 3},
+ {0x060f, 0x06de, 207},
+ {0x06e9, 0x06fd, 20},
+ {0x06fe, 0x07f6, 248},
+ {0x09f2, 0x09f3, 1},
+ {0x09fa, 0x09fb, 1},
+ {0x0af1, 0x0b70, 127},
+ {0x0bf3, 0x0bfa, 1},
+ {0x0c7f, 0x0d79, 250},
+ {0x0e3f, 0x0f01, 194},
+ {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},
+ {0x17db, 0x1940, 357},
+ {0x19de, 0x19ff, 1},
+ {0x1b61, 0x1b6a, 1},
+ {0x1b74, 0x1b7c, 1},
+ {0x1fbd, 0x1fbf, 2},
+ {0x1fc0, 0x1fc1, 1},
+ {0x1fcd, 0x1fcf, 1},
+ {0x1fdd, 0x1fdf, 1},
+ {0x1fed, 0x1fef, 1},
+ {0x1ffd, 0x1ffe, 1},
+ {0x2044, 0x2052, 14},
+ {0x207a, 0x207c, 1},
+ {0x208a, 0x208c, 1},
+ {0x20a0, 0x20b9, 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, 0x2140, 5},
+ {0x2141, 0x2144, 1},
+ {0x214a, 0x214d, 1},
+ {0x214f, 0x2190, 65},
+ {0x2191, 0x2328, 1},
+ {0x232b, 0x23f3, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x249c, 0x24e9, 1},
+ {0x2500, 0x26ff, 1},
+ {0x2701, 0x2767, 1},
+ {0x2794, 0x27c4, 1},
+ {0x27c7, 0x27ca, 1},
+ {0x27cc, 0x27ce, 2},
+ {0x27cf, 0x27e5, 1},
+ {0x27f0, 0x2982, 1},
+ {0x2999, 0x29d7, 1},
+ {0x29dc, 0x29fb, 1},
+ {0x29fe, 0x2b4c, 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},
+ {0x309b, 0x309c, 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},
+ {0xa700, 0xa716, 1},
+ {0xa720, 0xa721, 1},
+ {0xa789, 0xa78a, 1},
+ {0xa828, 0xa82b, 1},
+ {0xa836, 0xa839, 1},
+ {0xaa77, 0xaa79, 1},
+ {0xfb29, 0xfbb2, 137},
+ {0xfbb3, 0xfbc1, 1},
+ {0xfdfc, 0xfdfd, 1},
+ {0xfe62, 0xfe64, 2},
+ {0xfe65, 0xfe66, 1},
+ {0xfe69, 0xff04, 155},
+ {0xff0b, 0xff1c, 17},
+ {0xff1d, 0xff1e, 1},
+ {0xff3e, 0xff40, 2},
+ {0xff5c, 0xff5e, 2},
+ {0xffe0, 0xffe6, 1},
+ {0xffe8, 0xffee, 1},
+ {0xfffc, 0xfffd, 1},
+ },
+ R32: []Range32{
+ {0x10102, 0x10137, 53},
+ {0x10138, 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},
+ {0x1d6c1, 0x1d6db, 26},
+ {0x1d6fb, 0x1d715, 26},
+ {0x1d735, 0x1d74f, 26},
+ {0x1d76f, 0x1d789, 26},
+ {0x1d7a9, 0x1d7c3, 26},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f0a0, 0x1f0ae, 1},
+ {0x1f0b1, 0x1f0be, 1},
+ {0x1f0c1, 0x1f0cf, 1},
+ {0x1f0d1, 0x1f0df, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f130, 0x1f169, 1},
+ {0x1f170, 0x1f19a, 1},
+ {0x1f1e6, 0x1f202, 1},
+ {0x1f210, 0x1f23a, 1},
+ {0x1f240, 0x1f248, 1},
+ {0x1f250, 0x1f251, 1},
+ {0x1f300, 0x1f320, 1},
+ {0x1f330, 0x1f335, 1},
+ {0x1f337, 0x1f37c, 1},
+ {0x1f380, 0x1f393, 1},
+ {0x1f3a0, 0x1f3c4, 1},
+ {0x1f3c6, 0x1f3ca, 1},
+ {0x1f3e0, 0x1f3f0, 1},
+ {0x1f400, 0x1f43e, 1},
+ {0x1f440, 0x1f442, 2},
+ {0x1f443, 0x1f4f7, 1},
+ {0x1f4f9, 0x1f4fc, 1},
+ {0x1f500, 0x1f53d, 1},
+ {0x1f550, 0x1f567, 1},
+ {0x1f5fb, 0x1f5ff, 1},
+ {0x1f601, 0x1f610, 1},
+ {0x1f612, 0x1f614, 1},
+ {0x1f616, 0x1f61c, 2},
+ {0x1f61d, 0x1f61e, 1},
+ {0x1f620, 0x1f625, 1},
+ {0x1f628, 0x1f62b, 1},
+ {0x1f62d, 0x1f630, 3},
+ {0x1f631, 0x1f633, 1},
+ {0x1f635, 0x1f640, 1},
+ {0x1f645, 0x1f64f, 1},
+ {0x1f680, 0x1f6c5, 1},
+ {0x1f700, 0x1f773, 1},
+ },
+}
+
+var _Z = &RangeTable{
+ R16: []Range16{
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x2028, 0x2029, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
+ },
+}
+
+var _Me = &RangeTable{
+ R16: []Range16{
+ {0x0488, 0x0489, 1},
+ {0x20dd, 0x20e0, 1},
+ {0x20e2, 0x20e4, 1},
+ {0xa670, 0xa672, 1},
+ },
+}
+
+var _Mc = &RangeTable{
+ R16: []Range16{
+ {0x0903, 0x093b, 56},
+ {0x093e, 0x0940, 1},
+ {0x0949, 0x094c, 1},
+ {0x094e, 0x094f, 1},
+ {0x0982, 0x0983, 1},
+ {0x09be, 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, 0x1be7, 61},
+ {0x1bea, 0x1bec, 1},
+ {0x1bee, 0x1bf2, 4},
+ {0x1bf3, 0x1c24, 49},
+ {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, 0xabec, 1},
+ },
+ R32: []Range32{
+ {0x11000, 0x11000, 1},
+ {0x11002, 0x11082, 128},
+ {0x110b0, 0x110b2, 1},
+ {0x110b7, 0x110b8, 1},
+ {0x1d165, 0x1d166, 1},
+ {0x1d16d, 0x1d172, 1},
+ },
+}
+
+var _Mn = &RangeTable{
+ R16: []Range16{
+ {0x0300, 0x036f, 1},
+ {0x0483, 0x0487, 1},
+ {0x0591, 0x05bd, 1},
+ {0x05bf, 0x05c1, 2},
+ {0x05c2, 0x05c4, 2},
+ {0x05c5, 0x05c7, 2},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x065f, 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},
+ {0x0859, 0x085b, 1},
+ {0x0900, 0x0902, 1},
+ {0x093a, 0x093c, 2},
+ {0x0941, 0x0948, 1},
+ {0x094d, 0x0951, 4},
+ {0x0952, 0x0957, 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},
+ {0x0f8d, 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, 0x135d, 704},
+ {0x135e, 0x135f, 1},
+ {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},
+ {0x1be6, 0x1be8, 2},
+ {0x1be9, 0x1bed, 4},
+ {0x1bef, 0x1bf1, 1},
+ {0x1c2c, 0x1c33, 1},
+ {0x1c36, 0x1c37, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1dc0, 211},
+ {0x1dc1, 0x1de6, 1},
+ {0x1dfc, 0x1dff, 1},
+ {0x20d0, 0x20dc, 1},
+ {0x20e1, 0x20e5, 4},
+ {0x20e6, 0x20f0, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2d7f, 0x2de0, 97},
+ {0x2de1, 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},
+ },
+ R32: []Range32{
+ {0x101fd, 0x10a01, 2052},
+ {0x10a02, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x11001, 1474},
+ {0x11038, 0x11046, 1},
+ {0x11080, 0x11081, 1},
+ {0x110b3, 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 = &RangeTable{
+ R16: []Range16{
+ {0x2028, 0x2028, 1},
+ },
+}
+
+var _Zp = &RangeTable{
+ R16: []Range16{
+ {0x2029, 0x2029, 1},
+ },
+}
+
+var _Zs = &RangeTable{
+ R16: []Range16{
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
+ },
+}
+
+var _Cs = &RangeTable{
+ R16: []Range16{
+ {0xd800, 0xdfff, 1},
+ },
+}
+
+var _Co = &RangeTable{
+ R16: []Range16{
+ {0xe000, 0xf8ff, 1},
+ },
+ R32: []Range32{
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
+ },
+}
+
+var _Cf = &RangeTable{
+ R16: []Range16{
+ {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},
+ },
+ R32: []Range32{
+ {0x110bd, 0x1d173, 49334},
+ {0x1d174, 0x1d17a, 1},
+ {0xe0001, 0xe0020, 31},
+ {0xe0021, 0xe007f, 1},
+ },
+}
+
+var _Cc = &RangeTable{
+ R16: []Range16{
+ {0x0001, 0x001f, 1},
+ {0x007f, 0x009f, 1},
+ },
+}
+
+var _Po = &RangeTable{
+ R16: []Range16{
+ {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},
+ {0x085e, 0x0964, 262},
+ {0x0965, 0x0970, 11},
+ {0x0df4, 0x0e4f, 91},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f04, 0x0f12, 1},
+ {0x0f85, 0x0fd0, 75},
+ {0x0fd1, 0x0fd4, 1},
+ {0x0fd9, 0x0fda, 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},
+ {0x1a1e, 0x1a1f, 1},
+ {0x1aa0, 0x1aa6, 1},
+ {0x1aa8, 0x1aad, 1},
+ {0x1b5a, 0x1b60, 1},
+ {0x1bfc, 0x1bff, 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},
+ {0x2d70, 0x2e00, 144},
+ {0x2e01, 0x2e06, 5},
+ {0x2e07, 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, 0xff65, 1},
+ },
+ R32: []Range32{
+ {0x10100, 0x10100, 1},
+ {0x10101, 0x1039f, 670},
+ {0x103d0, 0x10857, 1159},
+ {0x1091f, 0x1093f, 32},
+ {0x10a50, 0x10a58, 1},
+ {0x10a7f, 0x10b39, 186},
+ {0x10b3a, 0x10b3f, 1},
+ {0x11047, 0x1104d, 1},
+ {0x110bb, 0x110bc, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _Pi = &RangeTable{
+ R16: []Range16{
+ {0x00ab, 0x2018, 8045},
+ {0x201b, 0x201c, 1},
+ {0x201f, 0x2039, 26},
+ {0x2e02, 0x2e04, 2},
+ {0x2e09, 0x2e0c, 3},
+ {0x2e1c, 0x2e20, 4},
+ },
+}
+
+var _Pf = &RangeTable{
+ R16: []Range16{
+ {0x00bb, 0x2019, 8030},
+ {0x201d, 0x203a, 29},
+ {0x2e03, 0x2e05, 2},
+ {0x2e0a, 0x2e0d, 3},
+ {0x2e1d, 0x2e21, 4},
+ },
+}
+
+var _Pe = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x005f, 0x203f, 8160},
+ {0x2040, 0x2054, 20},
+ {0xfe33, 0xfe34, 1},
+ {0xfe4d, 0xfe4f, 1},
+ {0xff3f, 0xff3f, 1},
+ },
+}
+
+var _Ps = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {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, 0x19d9, 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},
+ },
+ R32: []Range32{
+ {0x104a0, 0x104a9, 1},
+ {0x11066, 0x1106f, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ },
+}
+
+var _Nl = &RangeTable{
+ R16: []Range16{
+ {0x16ee, 0x16f0, 1},
+ {0x2160, 0x2182, 1},
+ {0x2185, 0x2188, 1},
+ {0x3007, 0x3021, 26},
+ {0x3022, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0xa6e6, 0xa6ef, 1},
+ },
+ R32: []Range32{
+ {0x10140, 0x10174, 1},
+ {0x10341, 0x1034a, 9},
+ {0x103d1, 0x103d5, 1},
+ {0x12400, 0x12462, 1},
+ },
+}
+
+var _No = &RangeTable{
+ R16: []Range16{
+ {0x00b2, 0x00b3, 1},
+ {0x00b9, 0x00bc, 3},
+ {0x00bd, 0x00be, 1},
+ {0x09f4, 0x09f9, 1},
+ {0x0b72, 0x0b77, 1},
+ {0x0bf0, 0x0bf2, 1},
+ {0x0c78, 0x0c7e, 1},
+ {0x0d70, 0x0d75, 1},
+ {0x0f2a, 0x0f33, 1},
+ {0x1369, 0x137c, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x19da, 0x2070, 1686},
+ {0x2074, 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},
+ },
+ R32: []Range32{
+ {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},
+ {0x11052, 0x11065, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1f100, 0x1f10a, 1},
+ },
+}
+
+var _So = &RangeTable{
+ R16: []Range16{
+ {0x00a6, 0x00a7, 1},
+ {0x00a9, 0x00ae, 5},
+ {0x00b0, 0x00b6, 6},
+ {0x0482, 0x060e, 396},
+ {0x060f, 0x06de, 207},
+ {0x06e9, 0x06fd, 20},
+ {0x06fe, 0x07f6, 248},
+ {0x09fa, 0x0b70, 374},
+ {0x0bf3, 0x0bf8, 1},
+ {0x0bfa, 0x0c7f, 133},
+ {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, 0x19de, 158},
+ {0x19df, 0x19ff, 1},
+ {0x1b61, 0x1b6a, 1},
+ {0x1b74, 0x1b7c, 1},
+ {0x2100, 0x2101, 1},
+ {0x2103, 0x2106, 1},
+ {0x2108, 0x2109, 1},
+ {0x2114, 0x2116, 2},
+ {0x2117, 0x211e, 7},
+ {0x211f, 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, 0x23f3, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x249c, 0x24e9, 1},
+ {0x2500, 0x25b6, 1},
+ {0x25b8, 0x25c0, 1},
+ {0x25c2, 0x25f7, 1},
+ {0x2600, 0x266e, 1},
+ {0x2670, 0x26ff, 1},
+ {0x2701, 0x2767, 1},
+ {0x2794, 0x27bf, 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, 0xfffd, 1},
+ },
+ R32: []Range32{
+ {0x10102, 0x10102, 1},
+ {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},
+ {0x1f0a0, 0x1f0ae, 1},
+ {0x1f0b1, 0x1f0be, 1},
+ {0x1f0c1, 0x1f0cf, 1},
+ {0x1f0d1, 0x1f0df, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f130, 0x1f169, 1},
+ {0x1f170, 0x1f19a, 1},
+ {0x1f1e6, 0x1f202, 1},
+ {0x1f210, 0x1f23a, 1},
+ {0x1f240, 0x1f248, 1},
+ {0x1f250, 0x1f251, 1},
+ {0x1f300, 0x1f320, 1},
+ {0x1f330, 0x1f335, 1},
+ {0x1f337, 0x1f37c, 1},
+ {0x1f380, 0x1f393, 1},
+ {0x1f3a0, 0x1f3c4, 1},
+ {0x1f3c6, 0x1f3ca, 1},
+ {0x1f3e0, 0x1f3f0, 1},
+ {0x1f400, 0x1f43e, 1},
+ {0x1f440, 0x1f442, 2},
+ {0x1f443, 0x1f4f7, 1},
+ {0x1f4f9, 0x1f4fc, 1},
+ {0x1f500, 0x1f53d, 1},
+ {0x1f550, 0x1f567, 1},
+ {0x1f5fb, 0x1f5ff, 1},
+ {0x1f601, 0x1f610, 1},
+ {0x1f612, 0x1f614, 1},
+ {0x1f616, 0x1f61c, 2},
+ {0x1f61d, 0x1f61e, 1},
+ {0x1f620, 0x1f625, 1},
+ {0x1f628, 0x1f62b, 1},
+ {0x1f62d, 0x1f630, 3},
+ {0x1f631, 0x1f633, 1},
+ {0x1f635, 0x1f640, 1},
+ {0x1f645, 0x1f64f, 1},
+ {0x1f680, 0x1f6c5, 1},
+ {0x1f700, 0x1f773, 1},
+ },
+}
+
+var _Sm = &RangeTable{
+ R16: []Range16{
+ {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},
+ {0x2118, 0x2140, 40},
+ {0x2141, 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, 0x27ce, 2},
+ {0x27cf, 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},
+ },
+ R32: []Range32{
+ {0x1d6c1, 0x1d6db, 26},
+ {0x1d6fb, 0x1d715, 26},
+ {0x1d735, 0x1d74f, 26},
+ {0x1d76f, 0x1d789, 26},
+ {0x1d7a9, 0x1d7c3, 26},
+ },
+}
+
+var _Sk = &RangeTable{
+ R16: []Range16{
+ {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},
+ {0xfbb2, 0xfbc1, 1},
+ {0xff3e, 0xff40, 2},
+ {0xffe3, 0xffe3, 1},
+ },
+}
+
+var _Sc = &RangeTable{
+ R16: []Range16{
+ {0x0024, 0x00a2, 126},
+ {0x00a3, 0x00a5, 1},
+ {0x060b, 0x09f2, 999},
+ {0x09f3, 0x09fb, 8},
+ {0x0af1, 0x0bf9, 264},
+ {0x0e3f, 0x17db, 2460},
+ {0x20a0, 0x20b9, 1},
+ {0xa838, 0xfdfc, 21956},
+ {0xfe69, 0xff04, 155},
+ {0xffe0, 0xffe1, 1},
+ {0xffe5, 0xffe6, 1},
+ },
+}
+
+var _Lu = &RangeTable{
+ R16: []Range16{
+ {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, 0x0526, 2},
+ {0x0531, 0x0556, 1},
+ {0x10a0, 0x10c5, 1},
+ {0x1e00, 0x1e94, 2},
+ {0x1e9e, 0x1efe, 2},
+ {0x1f08, 0x1f0f, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f28, 0x1f2f, 1},
+ {0x1f38, 0x1f3f, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f68, 0x1f6f, 1},
+ {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, 0xa66c, 2},
+ {0xa680, 0xa696, 2},
+ {0xa722, 0xa72e, 2},
+ {0xa732, 0xa76e, 2},
+ {0xa779, 0xa77d, 2},
+ {0xa77e, 0xa786, 2},
+ {0xa78b, 0xa78d, 2},
+ {0xa790, 0xa7a0, 16},
+ {0xa7a2, 0xa7a8, 2},
+ {0xff21, 0xff3a, 1},
+ },
+ R32: []Range32{
+ {0x10400, 0x10427, 1},
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x01c5, 0x01cb, 3},
+ {0x01f2, 0x1f88, 7574},
+ {0x1f89, 0x1f8f, 1},
+ {0x1f98, 0x1f9f, 1},
+ {0x1fa8, 0x1faf, 1},
+ {0x1fbc, 0x1fcc, 16},
+ {0x1ffc, 0x1ffc, 1},
+ },
+}
+
+var _Lo = &RangeTable{
+ R16: []Range16{
+ {0x01bb, 0x01c0, 5},
+ {0x01c1, 0x01c3, 1},
+ {0x0294, 0x05d0, 828},
+ {0x05d1, 0x05ea, 1},
+ {0x05f0, 0x05f2, 1},
+ {0x0620, 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},
+ {0x0840, 0x0858, 1},
+ {0x0904, 0x0939, 1},
+ {0x093d, 0x0950, 19},
+ {0x0958, 0x0961, 1},
+ {0x0972, 0x0977, 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},
+ {0x0cf1, 0x0cf2, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d3a, 1},
+ {0x0d3d, 0x0d4e, 17},
+ {0x0d60, 0x0d61, 1},
+ {0x0d7a, 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, 0x0f8c, 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},
+ {0x1bc0, 0x1be5, 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, 0x31ba, 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},
+ {0xab01, 0xab06, 1},
+ {0xab09, 0xab0e, 1},
+ {0xab11, 0xab16, 1},
+ {0xab20, 0xab26, 1},
+ {0xab28, 0xab2e, 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},
+ },
+ R32: []Range32{
+ {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},
+ {0x11003, 0x11037, 1},
+ {0x11083, 0x110af, 1},
+ {0x12000, 0x1236e, 1},
+ {0x13000, 0x1342e, 1},
+ {0x16800, 0x16a38, 1},
+ {0x1b000, 0x1b001, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 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.
+ 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 = _L // Letter/L is the set of Unicode letters, category L.
+ L = _L
+ 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.
+ Mark = _M // Mark/M is the set of Unicode mark characters, category M.
+ M = _M
+ 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.
+ Number = _N // Number/N is the set of Unicode number characters, category N.
+ N = _N
+ Other = _C // Other/C is the set of Unicode control and special characters, category C.
+ C = _C
+ 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.
+ Punct = _P // Punct/P is the set of Unicode punctuation characters, category P.
+ P = _P
+ 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.
+ Space = _Z // Space/Z is the set of Unicode space characters, category Z.
+ Z = _Z
+ Symbol = _S // Symbol/S is the set of Unicode symbol characters, category S.
+ S = _S
+ 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
@@ -2018,7 +2756,7 @@ var (
// DO NOT EDIT
// Scripts is the set of Unicode script tables.
-var Scripts = map[string][]Range{
+var Scripts = map[string]*RangeTable{
"Katakana": Katakana,
"Malayalam": Malayalam,
"Phags_Pa": Phags_Pa,
@@ -2116,973 +2854,1203 @@ var Scripts = map[string][]Range{
"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},
- {0x1b000, 0x1b000, 1},
-}
-
-var _Malayalam = []Range{
- {0x0d02, 0x0d03, 1},
- {0x0d05, 0x0d0c, 1},
- {0x0d0e, 0x0d10, 1},
- {0x0d12, 0x0d3a, 1},
- {0x0d3d, 0x0d44, 1},
- {0x0d46, 0x0d48, 1},
- {0x0d4a, 0x0d4e, 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, 0x209c, 1},
- {0x212a, 0x212b, 1},
- {0x2132, 0x2132, 1},
- {0x214e, 0x214e, 1},
- {0x2160, 0x2188, 1},
- {0x2c60, 0x2c7f, 1},
- {0xa722, 0xa787, 1},
- {0xa78b, 0xa78e, 1},
- {0xa790, 0xa791, 1},
- {0xa7a0, 0xa7a9, 1},
- {0xa7fa, 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},
- {0x065f, 0x065f, 1},
- {0x0670, 0x0670, 1},
- {0x0951, 0x0952, 1},
- {0x1cd0, 0x1cd2, 1},
- {0x1cd4, 0x1ce0, 1},
- {0x1ce2, 0x1ce8, 1},
- {0x1ced, 0x1ced, 1},
- {0x1dc0, 0x1de6, 1},
- {0x1dfc, 0x1dff, 1},
- {0x200c, 0x200d, 1},
- {0x20d0, 0x20f0, 1},
- {0x302a, 0x302d, 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{
- {0x02ea, 0x02eb, 1},
- {0x3105, 0x312d, 1},
- {0x31a0, 0x31ba, 1},
-}
-
-var _Imperial_Aramaic = []Range{
- {0x10840, 0x10855, 1},
- {0x10857, 0x1085f, 1},
-}
-
-var _Kaithi = []Range{
- {0x11080, 0x110c1, 1},
-}
-
-var _Mandaic = []Range{
- {0x0840, 0x085b, 1},
- {0x085e, 0x085e, 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, 0x02e9, 1},
- {0x02ec, 0x02ff, 1},
- {0x0374, 0x0374, 1},
- {0x037e, 0x037e, 1},
- {0x0385, 0x0385, 1},
- {0x0387, 0x0387, 1},
- {0x0589, 0x0589, 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},
- {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, 0x20b9, 1},
- {0x2100, 0x2125, 1},
- {0x2127, 0x2129, 1},
- {0x212c, 0x2131, 1},
- {0x2133, 0x214d, 1},
- {0x214f, 0x215f, 1},
- {0x2189, 0x2189, 1},
- {0x2190, 0x23f3, 1},
- {0x2400, 0x2426, 1},
- {0x2440, 0x244a, 1},
- {0x2460, 0x26ff, 1},
- {0x2701, 0x27ca, 1},
- {0x27cc, 0x27cc, 1},
- {0x27ce, 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},
- {0x1f0a0, 0x1f0ae, 1},
- {0x1f0b1, 0x1f0be, 1},
- {0x1f0c1, 0x1f0cf, 1},
- {0x1f0d1, 0x1f0df, 1},
- {0x1f100, 0x1f10a, 1},
- {0x1f110, 0x1f12e, 1},
- {0x1f130, 0x1f169, 1},
- {0x1f170, 0x1f19a, 1},
- {0x1f1e6, 0x1f1ff, 1},
- {0x1f201, 0x1f202, 1},
- {0x1f210, 0x1f23a, 1},
- {0x1f240, 0x1f248, 1},
- {0x1f250, 0x1f251, 1},
- {0x1f300, 0x1f320, 1},
- {0x1f330, 0x1f335, 1},
- {0x1f337, 0x1f37c, 1},
- {0x1f380, 0x1f393, 1},
- {0x1f3a0, 0x1f3c4, 1},
- {0x1f3c6, 0x1f3ca, 1},
- {0x1f3e0, 0x1f3f0, 1},
- {0x1f400, 0x1f43e, 1},
- {0x1f440, 0x1f440, 1},
- {0x1f442, 0x1f4f7, 1},
- {0x1f4f9, 0x1f4fc, 1},
- {0x1f500, 0x1f53d, 1},
- {0x1f550, 0x1f567, 1},
- {0x1f5fb, 0x1f5ff, 1},
- {0x1f601, 0x1f610, 1},
- {0x1f612, 0x1f614, 1},
- {0x1f616, 0x1f616, 1},
- {0x1f618, 0x1f618, 1},
- {0x1f61a, 0x1f61a, 1},
- {0x1f61c, 0x1f61e, 1},
- {0x1f620, 0x1f625, 1},
- {0x1f628, 0x1f62b, 1},
- {0x1f62d, 0x1f62d, 1},
- {0x1f630, 0x1f633, 1},
- {0x1f635, 0x1f640, 1},
- {0x1f645, 0x1f64f, 1},
- {0x1f680, 0x1f6c5, 1},
- {0x1f700, 0x1f773, 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},
- {0x0cf1, 0x0cf2, 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 _Brahmi = []Range{
- {0x11000, 0x1104d, 1},
- {0x11052, 0x1106f, 1},
-}
-
-var _Arabic = []Range{
- {0x0600, 0x0603, 1},
- {0x0606, 0x060b, 1},
- {0x060d, 0x061a, 1},
- {0x061e, 0x061e, 1},
- {0x0620, 0x063f, 1},
- {0x0641, 0x064a, 1},
- {0x0656, 0x065e, 1},
- {0x066a, 0x066f, 1},
- {0x0671, 0x06dc, 1},
- {0x06de, 0x06ff, 1},
- {0x0750, 0x077f, 1},
- {0xfb50, 0xfbc1, 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, 0x0f97, 1},
- {0x0f99, 0x0fbc, 1},
- {0x0fbe, 0x0fcc, 1},
- {0x0fce, 0x0fd4, 1},
- {0x0fd9, 0x0fda, 1},
-}
-
-var _Coptic = []Range{
- {0x03e2, 0x03ef, 1},
- {0x2c80, 0x2cf1, 1},
- {0x2cf9, 0x2cff, 1},
-}
-
-var _Hiragana = []Range{
- {0x3041, 0x3096, 1},
- {0x309d, 0x309f, 1},
- {0x1b001, 0x1b001, 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},
- {0x302e, 0x302f, 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, 0x0b77, 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},
- {0x135d, 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},
- {0xab01, 0xab06, 1},
- {0xab09, 0xab0e, 1},
- {0xab11, 0xab16, 1},
- {0xab20, 0xab26, 1},
- {0xab28, 0xab2e, 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 _Batak = []Range{
- {0x1bc0, 0x1bf3, 1},
- {0x1bfc, 0x1bff, 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},
- {0x16800, 0x16a38, 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, 0x0950, 1},
- {0x0953, 0x0963, 1},
- {0x0966, 0x096f, 1},
- {0x0971, 0x0977, 1},
- {0x0979, 0x097f, 1},
- {0xa8e0, 0xa8fb, 1},
-}
-
-var _Lydian = []Range{
- {0x10920, 0x10939, 1},
- {0x1093f, 0x1093f, 1},
-}
-
-var _Tifinagh = []Range{
- {0x2d30, 0x2d65, 1},
- {0x2d6f, 0x2d70, 1},
- {0x2d7f, 0x2d7f, 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, 0x0527, 1},
- {0x1d2b, 0x1d2b, 1},
- {0x1d78, 0x1d78, 1},
- {0x2de0, 0x2dff, 1},
- {0xa640, 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},
- {0x2b740, 0x2b81d, 1},
- {0x2f800, 0x2fa1d, 1},
-}
-
-var _Gothic = []Range{
- {0x10330, 0x1034a, 1},
+var _Katakana = &RangeTable{
+ R16: []Range16{
+ {0x30a1, 0x30fa, 1},
+ {0x30fd, 0x30ff, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x32d0, 0x32fe, 1},
+ {0x3300, 0x3357, 1},
+ {0xff66, 0xff6f, 1},
+ {0xff71, 0xff9d, 1},
+ },
+ R32: []Range32{
+ {0x1b000, 0x1b000, 1},
+ },
+}
+
+var _Malayalam = &RangeTable{
+ R16: []Range16{
+ {0x0d02, 0x0d03, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d3a, 1},
+ {0x0d3d, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4e, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0d60, 0x0d63, 1},
+ {0x0d66, 0x0d75, 1},
+ {0x0d79, 0x0d7f, 1},
+ },
+}
+
+var _Phags_Pa = &RangeTable{
+ R16: []Range16{
+ {0xa840, 0xa877, 1},
+ },
+}
+
+var _Inscriptional_Parthian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b40, 0x10b55, 1},
+ {0x10b58, 0x10b5f, 1},
+ },
+}
+
+var _Latin = &RangeTable{
+ R16: []Range16{
+ {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, 0x209c, 1},
+ {0x212a, 0x212b, 1},
+ {0x2132, 0x2132, 1},
+ {0x214e, 0x214e, 1},
+ {0x2160, 0x2188, 1},
+ {0x2c60, 0x2c7f, 1},
+ {0xa722, 0xa787, 1},
+ {0xa78b, 0xa78e, 1},
+ {0xa790, 0xa791, 1},
+ {0xa7a0, 0xa7a9, 1},
+ {0xa7fa, 0xa7ff, 1},
+ {0xfb00, 0xfb06, 1},
+ {0xff21, 0xff3a, 1},
+ {0xff41, 0xff5a, 1},
+ },
+}
+
+var _Inscriptional_Pahlavi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b60, 0x10b72, 1},
+ {0x10b78, 0x10b7f, 1},
+ },
+}
+
+var _Osmanya = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10480, 0x1049d, 1},
+ {0x104a0, 0x104a9, 1},
+ },
+}
+
+var _Khmer = &RangeTable{
+ R16: []Range16{
+ {0x1780, 0x17dd, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x19e0, 0x19ff, 1},
+ },
+}
+
+var _Inherited = &RangeTable{
+ R16: []Range16{
+ {0x0300, 0x036f, 1},
+ {0x0485, 0x0486, 1},
+ {0x064b, 0x0655, 1},
+ {0x065f, 0x065f, 1},
+ {0x0670, 0x0670, 1},
+ {0x0951, 0x0952, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1ced, 1},
+ {0x1dc0, 0x1de6, 1},
+ {0x1dfc, 0x1dff, 1},
+ {0x200c, 0x200d, 1},
+ {0x20d0, 0x20f0, 1},
+ {0x302a, 0x302d, 1},
+ {0x3099, 0x309a, 1},
+ {0xfe00, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ },
+ R32: []Range32{
+ {0x101fd, 0x101fd, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0xe0100, 0xe01ef, 1},
+ },
+}
+
+var _Telugu = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x0800, 0x082d, 1},
+ {0x0830, 0x083e, 1},
+ },
+}
+
+var _Bopomofo = &RangeTable{
+ R16: []Range16{
+ {0x02ea, 0x02eb, 1},
+ {0x3105, 0x312d, 1},
+ {0x31a0, 0x31ba, 1},
+ },
+}
+
+var _Imperial_Aramaic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10840, 0x10855, 1},
+ {0x10857, 0x1085f, 1},
+ },
+}
+
+var _Kaithi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11080, 0x110c1, 1},
+ },
+}
+
+var _Mandaic = &RangeTable{
+ R16: []Range16{
+ {0x0840, 0x085b, 1},
+ {0x085e, 0x085e, 1},
+ },
+}
+
+var _Old_South_Arabian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10a60, 0x10a7f, 1},
+ },
+}
+
+var _Kayah_Li = &RangeTable{
+ R16: []Range16{
+ {0xa900, 0xa92f, 1},
+ },
+}
+
+var _New_Tai_Lue = &RangeTable{
+ R16: []Range16{
+ {0x1980, 0x19ab, 1},
+ {0x19b0, 0x19c9, 1},
+ {0x19d0, 0x19da, 1},
+ {0x19de, 0x19df, 1},
+ },
+}
+
+var _Tai_Le = &RangeTable{
+ R16: []Range16{
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+ },
+}
+
+var _Kharoshthi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {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, 0x02e9, 1},
+ {0x02ec, 0x02ff, 1},
+ {0x0374, 0x0374, 1},
+ {0x037e, 0x037e, 1},
+ {0x0385, 0x0385, 1},
+ {0x0387, 0x0387, 1},
+ {0x0589, 0x0589, 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},
+ {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, 0x20b9, 1},
+ {0x2100, 0x2125, 1},
+ {0x2127, 0x2129, 1},
+ {0x212c, 0x2131, 1},
+ {0x2133, 0x214d, 1},
+ {0x214f, 0x215f, 1},
+ {0x2189, 0x2189, 1},
+ {0x2190, 0x23f3, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x2460, 0x26ff, 1},
+ {0x2701, 0x27ca, 1},
+ {0x27cc, 0x27cc, 1},
+ {0x27ce, 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},
+ },
+ R32: []Range32{
+ {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},
+ {0x1f0a0, 0x1f0ae, 1},
+ {0x1f0b1, 0x1f0be, 1},
+ {0x1f0c1, 0x1f0cf, 1},
+ {0x1f0d1, 0x1f0df, 1},
+ {0x1f100, 0x1f10a, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f130, 0x1f169, 1},
+ {0x1f170, 0x1f19a, 1},
+ {0x1f1e6, 0x1f1ff, 1},
+ {0x1f201, 0x1f202, 1},
+ {0x1f210, 0x1f23a, 1},
+ {0x1f240, 0x1f248, 1},
+ {0x1f250, 0x1f251, 1},
+ {0x1f300, 0x1f320, 1},
+ {0x1f330, 0x1f335, 1},
+ {0x1f337, 0x1f37c, 1},
+ {0x1f380, 0x1f393, 1},
+ {0x1f3a0, 0x1f3c4, 1},
+ {0x1f3c6, 0x1f3ca, 1},
+ {0x1f3e0, 0x1f3f0, 1},
+ {0x1f400, 0x1f43e, 1},
+ {0x1f440, 0x1f440, 1},
+ {0x1f442, 0x1f4f7, 1},
+ {0x1f4f9, 0x1f4fc, 1},
+ {0x1f500, 0x1f53d, 1},
+ {0x1f550, 0x1f567, 1},
+ {0x1f5fb, 0x1f5ff, 1},
+ {0x1f601, 0x1f610, 1},
+ {0x1f612, 0x1f614, 1},
+ {0x1f616, 0x1f616, 1},
+ {0x1f618, 0x1f618, 1},
+ {0x1f61a, 0x1f61a, 1},
+ {0x1f61c, 0x1f61e, 1},
+ {0x1f620, 0x1f625, 1},
+ {0x1f628, 0x1f62b, 1},
+ {0x1f62d, 0x1f62d, 1},
+ {0x1f630, 0x1f633, 1},
+ {0x1f635, 0x1f640, 1},
+ {0x1f645, 0x1f64f, 1},
+ {0x1f680, 0x1f6c5, 1},
+ {0x1f700, 0x1f773, 1},
+ {0xe0001, 0xe0001, 1},
+ {0xe0020, 0xe007f, 1},
+ },
+}
+
+var _Kannada = &RangeTable{
+ R16: []Range16{
+ {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},
+ {0x0cf1, 0x0cf2, 1},
+ },
+}
+
+var _Old_Turkic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10c00, 0x10c48, 1},
+ },
+}
+
+var _Tamil = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1714, 1},
+ },
+}
+
+var _Brahmi = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x11000, 0x1104d, 1},
+ {0x11052, 0x1106f, 1},
+ },
+}
+
+var _Arabic = &RangeTable{
+ R16: []Range16{
+ {0x0600, 0x0603, 1},
+ {0x0606, 0x060b, 1},
+ {0x060d, 0x061a, 1},
+ {0x061e, 0x061e, 1},
+ {0x0620, 0x063f, 1},
+ {0x0641, 0x064a, 1},
+ {0x0656, 0x065e, 1},
+ {0x066a, 0x066f, 1},
+ {0x0671, 0x06dc, 1},
+ {0x06de, 0x06ff, 1},
+ {0x0750, 0x077f, 1},
+ {0xfb50, 0xfbc1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfc, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ },
+ R32: []Range32{
+ {0x10e60, 0x10e7e, 1},
+ },
+}
+
+var _Tagbanwa = &RangeTable{
+ R16: []Range16{
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1772, 0x1773, 1},
+ },
+}
+
+var _Canadian_Aboriginal = &RangeTable{
+ R16: []Range16{
+ {0x1400, 0x167f, 1},
+ {0x18b0, 0x18f5, 1},
+ },
+}
+
+var _Tibetan = &RangeTable{
+ R16: []Range16{
+ {0x0f00, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f71, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fbe, 0x0fcc, 1},
+ {0x0fce, 0x0fd4, 1},
+ {0x0fd9, 0x0fda, 1},
+ },
+}
+
+var _Coptic = &RangeTable{
+ R16: []Range16{
+ {0x03e2, 0x03ef, 1},
+ {0x2c80, 0x2cf1, 1},
+ {0x2cf9, 0x2cff, 1},
+ },
+}
+
+var _Hiragana = &RangeTable{
+ R16: []Range16{
+ {0x3041, 0x3096, 1},
+ {0x309d, 0x309f, 1},
+ },
+ R32: []Range32{
+ {0x1b001, 0x1b001, 1},
+ {0x1f200, 0x1f200, 1},
+ },
+}
+
+var _Limbu = &RangeTable{
+ R16: []Range16{
+ {0x1900, 0x191c, 1},
+ {0x1920, 0x192b, 1},
+ {0x1930, 0x193b, 1},
+ {0x1940, 0x1940, 1},
+ {0x1944, 0x194f, 1},
+ },
+}
+
+var _Egyptian_Hieroglyphs = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x13000, 0x1342e, 1},
+ },
+}
+
+var _Avestan = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10b00, 0x10b35, 1},
+ {0x10b39, 0x10b3f, 1},
+ },
+}
+
+var _Myanmar = &RangeTable{
+ R16: []Range16{
+ {0x1000, 0x109f, 1},
+ {0xaa60, 0xaa7b, 1},
+ },
+}
+
+var _Armenian = &RangeTable{
+ R16: []Range16{
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x055f, 1},
+ {0x0561, 0x0587, 1},
+ {0x058a, 0x058a, 1},
+ {0xfb13, 0xfb17, 1},
+ },
+}
+
+var _Sinhala = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {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},
+ },
+ R32: []Range32{
+ {0x10140, 0x1018a, 1},
+ {0x1d200, 0x1d245, 1},
+ },
+}
+
+var _Cham = &RangeTable{
+ R16: []Range16{
+ {0xaa00, 0xaa36, 1},
+ {0xaa40, 0xaa4d, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xaa5c, 0xaa5f, 1},
+ },
+}
+
+var _Hebrew = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0xabc0, 0xabed, 1},
+ {0xabf0, 0xabf9, 1},
+ },
+}
+
+var _Saurashtra = &RangeTable{
+ R16: []Range16{
+ {0xa880, 0xa8c4, 1},
+ {0xa8ce, 0xa8d9, 1},
+ },
+}
+
+var _Hangul = &RangeTable{
+ R16: []Range16{
+ {0x1100, 0x11ff, 1},
+ {0x302e, 0x302f, 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 = &RangeTable{
+ R16: []Range16{
+ {0x16a0, 0x16ea, 1},
+ {0x16ee, 0x16f0, 1},
+ },
+}
+
+var _Deseret = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10400, 0x1044f, 1},
+ },
+}
+
+var _Lisu = &RangeTable{
+ R16: []Range16{
+ {0xa4d0, 0xa4ff, 1},
+ },
+}
+
+var _Sundanese = &RangeTable{
+ R16: []Range16{
+ {0x1b80, 0x1baa, 1},
+ {0x1bae, 0x1bb9, 1},
+ },
+}
+
+var _Glagolitic = &RangeTable{
+ R16: []Range16{
+ {0x2c00, 0x2c2e, 1},
+ {0x2c30, 0x2c5e, 1},
+ },
+}
+
+var _Oriya = &RangeTable{
+ R16: []Range16{
+ {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, 0x0b77, 1},
+ },
+}
+
+var _Buhid = &RangeTable{
+ R16: []Range16{
+ {0x1740, 0x1753, 1},
+ },
+}
+
+var _Ethiopic = &RangeTable{
+ R16: []Range16{
+ {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},
+ {0x135d, 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},
+ {0xab01, 0xab06, 1},
+ {0xab09, 0xab0e, 1},
+ {0xab11, 0xab16, 1},
+ {0xab20, 0xab26, 1},
+ {0xab28, 0xab2e, 1},
+ },
+}
+
+var _Javanese = &RangeTable{
+ R16: []Range16{
+ {0xa980, 0xa9cd, 1},
+ {0xa9cf, 0xa9d9, 1},
+ {0xa9de, 0xa9df, 1},
+ },
+}
+
+var _Syloti_Nagri = &RangeTable{
+ R16: []Range16{
+ {0xa800, 0xa82b, 1},
+ },
+}
+
+var _Vai = &RangeTable{
+ R16: []Range16{
+ {0xa500, 0xa62b, 1},
+ },
+}
+
+var _Cherokee = &RangeTable{
+ R16: []Range16{
+ {0x13a0, 0x13f4, 1},
+ },
+}
+
+var _Ogham = &RangeTable{
+ R16: []Range16{
+ {0x1680, 0x169c, 1},
+ },
+}
+
+var _Batak = &RangeTable{
+ R16: []Range16{
+ {0x1bc0, 0x1bf3, 1},
+ {0x1bfc, 0x1bff, 1},
+ },
+}
+
+var _Syriac = &RangeTable{
+ R16: []Range16{
+ {0x0700, 0x070d, 1},
+ {0x070f, 0x074a, 1},
+ {0x074d, 0x074f, 1},
+ },
+}
+
+var _Gurmukhi = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x1a20, 0x1a5e, 1},
+ {0x1a60, 0x1a7c, 1},
+ {0x1a7f, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1aa0, 0x1aad, 1},
+ },
+}
+
+var _Ol_Chiki = &RangeTable{
+ R16: []Range16{
+ {0x1c50, 0x1c7f, 1},
+ },
+}
+
+var _Mongolian = &RangeTable{
+ R16: []Range16{
+ {0x1800, 0x1801, 1},
+ {0x1804, 0x1804, 1},
+ {0x1806, 0x180e, 1},
+ {0x1810, 0x1819, 1},
+ {0x1820, 0x1877, 1},
+ {0x1880, 0x18aa, 1},
+ },
+}
+
+var _Hanunoo = &RangeTable{
+ R16: []Range16{
+ {0x1720, 0x1734, 1},
+ },
+}
+
+var _Cypriot = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x10808, 1},
+ {0x1080a, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083c, 1},
+ {0x1083f, 0x1083f, 1},
+ },
+}
+
+var _Buginese = &RangeTable{
+ R16: []Range16{
+ {0x1a00, 0x1a1b, 1},
+ {0x1a1e, 0x1a1f, 1},
+ },
+}
+
+var _Bamum = &RangeTable{
+ R16: []Range16{
+ {0xa6a0, 0xa6f7, 1},
+ },
+ R32: []Range32{
+ {0x16800, 0x16a38, 1},
+ },
+}
+
+var _Lepcha = &RangeTable{
+ R16: []Range16{
+ {0x1c00, 0x1c37, 1},
+ {0x1c3b, 0x1c49, 1},
+ {0x1c4d, 0x1c4f, 1},
+ },
+}
+
+var _Thaana = &RangeTable{
+ R16: []Range16{
+ {0x0780, 0x07b1, 1},
+ },
+}
+
+var _Old_Persian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103d5, 1},
+ },
+}
+
+var _Cuneiform = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x12000, 0x1236e, 1},
+ {0x12400, 0x12462, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _Rejang = &RangeTable{
+ R16: []Range16{
+ {0xa930, 0xa953, 1},
+ {0xa95f, 0xa95f, 1},
+ },
+}
+
+var _Georgian = &RangeTable{
+ R16: []Range16{
+ {0x10a0, 0x10c5, 1},
+ {0x10d0, 0x10fa, 1},
+ {0x10fc, 0x10fc, 1},
+ {0x2d00, 0x2d25, 1},
+ },
+}
+
+var _Shavian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10450, 0x1047f, 1},
+ },
+}
+
+var _Lycian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10280, 0x1029c, 1},
+ },
+}
+
+var _Nko = &RangeTable{
+ R16: []Range16{
+ {0x07c0, 0x07fa, 1},
+ },
+}
+
+var _Yi = &RangeTable{
+ R16: []Range16{
+ {0xa000, 0xa48c, 1},
+ {0xa490, 0xa4c6, 1},
+ },
+}
+
+var _Lao = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+ },
+}
+
+var _Old_Italic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10300, 0x1031e, 1},
+ {0x10320, 0x10323, 1},
+ },
+}
+
+var _Tai_Viet = &RangeTable{
+ R16: []Range16{
+ {0xaa80, 0xaac2, 1},
+ {0xaadb, 0xaadf, 1},
+ },
+}
+
+var _Devanagari = &RangeTable{
+ R16: []Range16{
+ {0x0900, 0x0950, 1},
+ {0x0953, 0x0963, 1},
+ {0x0966, 0x096f, 1},
+ {0x0971, 0x0977, 1},
+ {0x0979, 0x097f, 1},
+ {0xa8e0, 0xa8fb, 1},
+ },
+}
+
+var _Lydian = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10920, 0x10939, 1},
+ {0x1093f, 0x1093f, 1},
+ },
+}
+
+var _Tifinagh = &RangeTable{
+ R16: []Range16{
+ {0x2d30, 0x2d65, 1},
+ {0x2d6f, 0x2d70, 1},
+ {0x2d7f, 0x2d7f, 1},
+ },
+}
+
+var _Ugaritic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10380, 0x1039d, 1},
+ {0x1039f, 0x1039f, 1},
+ },
+}
+
+var _Thai = &RangeTable{
+ R16: []Range16{
+ {0x0e01, 0x0e3a, 1},
+ {0x0e40, 0x0e5b, 1},
+ },
+}
+
+var _Cyrillic = &RangeTable{
+ R16: []Range16{
+ {0x0400, 0x0484, 1},
+ {0x0487, 0x0527, 1},
+ {0x1d2b, 0x1d2b, 1},
+ {0x1d78, 0x1d78, 1},
+ {0x2de0, 0x2dff, 1},
+ {0xa640, 0xa673, 1},
+ {0xa67c, 0xa697, 1},
+ },
+}
+
+var _Gujarati = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x102a0, 0x102d0, 1},
+ },
+}
+
+var _Phoenician = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10900, 0x1091b, 1},
+ {0x1091f, 0x1091f, 1},
+ },
+}
+
+var _Balinese = &RangeTable{
+ R16: []Range16{
+ {0x1b00, 0x1b4b, 1},
+ {0x1b50, 0x1b7c, 1},
+ },
+}
+
+var _Braille = &RangeTable{
+ R16: []Range16{
+ {0x2800, 0x28ff, 1},
+ },
+}
+
+var _Han = &RangeTable{
+ R16: []Range16{
+ {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},
+ },
+ R32: []Range32{
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
+ },
+}
+
+var _Gothic = &RangeTable{
+ R16: []Range16{},
+ R32: []Range32{
+ {0x10330, 0x1034a, 1},
+ },
}
var (
@@ -3188,7 +4156,7 @@ var (
// DO NOT EDIT
// Properties is the set of Unicode property tables.
-var Properties = map[string][]Range{
+var Properties = map[string]*RangeTable{
"Pattern_Syntax": Pattern_Syntax,
"Other_ID_Start": Other_ID_Start,
"Pattern_White_Space": Pattern_White_Space,
@@ -3223,837 +4191,927 @@ var Properties = map[string][]Range{
"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},
- {0x0673, 0x0673, 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},
- {0x085e, 0x085e, 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},
- {0x11047, 0x1104d, 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},
- {0x19da, 0x19da, 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},
- {0x2107, 0x2107, 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},
- {0x2b740, 0x2b81d, 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},
- {0x1735, 0x1736, 1},
- {0x1803, 0x1803, 1},
- {0x1809, 0x1809, 1},
- {0x1944, 0x1945, 1},
- {0x1aa8, 0x1aab, 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},
- {0x10a56, 0x10a57, 1},
- {0x11047, 0x11048, 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, 0x065f, 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},
- {0x093a, 0x093b, 1},
- {0x093e, 0x094c, 1},
- {0x094e, 0x094f, 1},
- {0x0955, 0x0957, 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},
- {0x0f8d, 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},
- {0x1be7, 0x1bf1, 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},
- {0xa9b4, 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},
- {0x11000, 0x11002, 1},
- {0x11038, 0x11045, 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},
- {0x2b740, 0x2b81d, 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 _Pattern_Syntax = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x2118, 0x2118, 1},
+ {0x212e, 0x212e, 1},
+ {0x309b, 0x309c, 1},
+ },
+}
+
+var _Pattern_White_Space = &RangeTable{
+ R16: []Range16{
+ {0x0009, 0x000d, 1},
+ {0x0020, 0x0020, 1},
+ {0x0085, 0x0085, 1},
+ {0x200e, 0x200f, 1},
+ {0x2028, 0x2029, 1},
+ },
+}
+
+var _Other_Lowercase = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {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},
+ },
+ R32: []Range32{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
+ {0xff10, 0xff19, 1},
+ {0xff21, 0xff26, 1},
+ {0xff41, 0xff46, 1},
+ },
+}
+
+var _ASCII_Hex_Digit = &RangeTable{
+ R16: []Range16{
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
+ },
+}
+
+var _Deprecated = &RangeTable{
+ R16: []Range16{
+ {0x0149, 0x0149, 1},
+ {0x0673, 0x0673, 1},
+ {0x0f77, 0x0f77, 1},
+ {0x0f79, 0x0f79, 1},
+ {0x17a3, 0x17a4, 1},
+ {0x206a, 0x206f, 1},
+ {0x2329, 0x232a, 1},
+ },
+ R32: []Range32{
+ {0xe0001, 0xe0001, 1},
+ {0xe0020, 0xe007f, 1},
+ },
+}
+
+var _Terminal_Punctuation = &RangeTable{
+ R16: []Range16{
+ {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},
+ {0x085e, 0x085e, 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},
+ },
+ R32: []Range32{
+ {0x1039f, 0x1039f, 1},
+ {0x103d0, 0x103d0, 1},
+ {0x10857, 0x10857, 1},
+ {0x1091f, 0x1091f, 1},
+ {0x10b3a, 0x10b3f, 1},
+ {0x11047, 0x1104d, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
+ },
+}
+
+var _Quotation_Mark = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x00b7, 0x00b7, 1},
+ {0x0387, 0x0387, 1},
+ {0x1369, 0x1371, 1},
+ {0x19da, 0x19da, 1},
+ },
+}
+
+var _Bidi_Control = &RangeTable{
+ R16: []Range16{
+ {0x200e, 0x200f, 1},
+ {0x202a, 0x202e, 1},
+ },
+}
+
+var _Variation_Selector = &RangeTable{
+ R16: []Range16{
+ {0x180b, 0x180d, 1},
+ {0xfe00, 0xfe0f, 1},
+ },
+ R32: []Range32{
+ {0xe0100, 0xe01ef, 1},
+ },
+}
+
+var _Noncharacter_Code_Point = &RangeTable{
+ R16: []Range16{
+ {0xfdd0, 0xfdef, 1},
+ {0xfffe, 0xffff, 1},
+ },
+ R32: []Range32{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {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},
+ {0x2107, 0x2107, 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},
+ },
+ R32: []Range32{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {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},
+ },
+ R32: []Range32{
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ },
+}
+
+var _Hyphen = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x2ff0, 0x2ff1, 1},
+ {0x2ff4, 0x2ffb, 1},
+ },
+}
+
+var _Logical_Order_Exception = &RangeTable{
+ R16: []Range16{
+ {0x0e40, 0x0e44, 1},
+ {0x0ec0, 0x0ec4, 1},
+ {0xaab5, 0xaab6, 1},
+ {0xaab9, 0xaab9, 1},
+ {0xaabb, 0xaabc, 1},
+ },
+}
+
+var _Radical = &RangeTable{
+ R16: []Range16{
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ },
+}
+
+var _Other_Uppercase = &RangeTable{
+ R16: []Range16{
+ {0x2160, 0x216f, 1},
+ {0x24b6, 0x24cf, 1},
+ },
+}
+
+var _STerm = &RangeTable{
+ R16: []Range16{
+ {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},
+ {0x1735, 0x1736, 1},
+ {0x1803, 0x1803, 1},
+ {0x1809, 0x1809, 1},
+ {0x1944, 0x1945, 1},
+ {0x1aa8, 0x1aab, 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},
+ },
+ R32: []Range32{
+ {0x10a56, 0x10a57, 1},
+ {0x11047, 0x11048, 1},
+ {0x110be, 0x110c1, 1},
+ },
+}
+
+var _Other_Alphabetic = &RangeTable{
+ R16: []Range16{
+ {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, 0x065f, 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},
+ {0x093a, 0x093b, 1},
+ {0x093e, 0x094c, 1},
+ {0x094e, 0x094f, 1},
+ {0x0955, 0x0957, 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},
+ {0x0f8d, 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},
+ {0x1be7, 0x1bf1, 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},
+ {0xa9b4, 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},
+ },
+ R32: []Range32{
+ {0x10a01, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x11000, 0x11002, 1},
+ {0x11038, 0x11045, 1},
+ {0x11082, 0x11082, 1},
+ {0x110b0, 0x110b8, 1},
+ },
+}
+
+var _Diacritic = &RangeTable{
+ R16: []Range16{
+ {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},
+ },
+ R32: []Range32{
+ {0x110b9, 0x110ba, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d16d, 0x1d172, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ },
+}
+
+var _Extender = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x200c, 0x200d, 1},
+ },
+}
+
+var _Ideographic = &RangeTable{
+ R16: []Range16{
+ {0x3006, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ },
+ R32: []Range32{
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2b740, 0x2b81d, 1},
+ {0x2f800, 0x2fa1d, 1},
+ },
+}
+
+var _Dash = &RangeTable{
+ R16: []Range16{
+ {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 = &RangeTable{
+ R16: []Range16{
+ {0x2ff2, 0x2ff3, 1},
+ },
+}
+
+var _Other_Grapheme_Extend = &RangeTable{
+ R16: []Range16{
+ {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},
+ },
+ R32: []Range32{
+ {0x1d165, 0x1d165, 1},
+ {0x1d16e, 0x1d172, 1},
+ },
+}
+
+var _Other_Default_Ignorable_Code_Point = &RangeTable{
+ R16: []Range16{
+ {0x034f, 0x034f, 1},
+ {0x115f, 0x1160, 1},
+ {0x2065, 0x2069, 1},
+ {0x3164, 0x3164, 1},
+ {0xffa0, 0xffa0, 1},
+ {0xfff0, 0xfff8, 1},
+ },
+ R32: []Range32{
+ {0xe0000, 0xe0000, 1},
+ {0xe0002, 0xe001f, 1},
+ {0xe0080, 0xe00ff, 1},
+ {0xe01f0, 0xe0fff, 1},
+ },
+}
+
+var _White_Space = &RangeTable{
+ R16: []Range16{
+ {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 (
@@ -4092,7 +5150,7 @@ var (
)
// Generated by running
-// maketables --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt
+// maketables --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.0.0/ucd/CaseFolding.txt
// DO NOT EDIT
// CaseRanges is the table describing case mappings for all letters with
@@ -4208,6 +5266,7 @@ var _CaseRanges = []CaseRange{
{0x028A, 0x028B, d{-217, 0, -217}},
{0x028C, 0x028C, d{-71, 0, -71}},
{0x0292, 0x0292, d{-219, 0, -219}},
+ {0x0345, 0x0345, d{84, 0, 84}},
{0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
{0x0376, 0x0377, d{UpperLower, UpperLower, UpperLower}},
{0x037B, 0x037D, d{130, 0, 130}},
@@ -4317,7 +5376,11 @@ var _CaseRanges = []CaseRange{
{0x212B, 0x212B, d{0, -8262, 0}},
{0x2132, 0x2132, d{0, 28, 0}},
{0x214E, 0x214E, d{-28, 0, -28}},
+ {0x2160, 0x216F, d{0, 16, 0}},
+ {0x2170, 0x217F, d{-16, 0, -16}},
{0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}},
+ {0x24B6, 0x24CF, d{0, 26, 0}},
+ {0x24D0, 0x24E9, d{-26, 0, -26}},
{0x2C00, 0x2C2E, d{0, 48, 0}},
{0x2C30, 0x2C5E, d{-48, 0, -48}},
{0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}},
@@ -4353,3 +5416,611 @@ var _CaseRanges = []CaseRange{
{0x10400, 0x10427, d{0, 40, 0}},
{0x10428, 0x1044F, d{-40, 0, -40}},
}
+var properties = [MaxLatin1 + 1]uint8{
+ 0x00: pC, // '\x00'
+ 0x01: pC, // '\x01'
+ 0x02: pC, // '\x02'
+ 0x03: pC, // '\x03'
+ 0x04: pC, // '\x04'
+ 0x05: pC, // '\x05'
+ 0x06: pC, // '\x06'
+ 0x07: pC, // '\a'
+ 0x08: pC, // '\b'
+ 0x09: pC, // '\t'
+ 0x0A: pC, // '\n'
+ 0x0B: pC, // '\v'
+ 0x0C: pC, // '\f'
+ 0x0D: pC, // '\r'
+ 0x0E: pC, // '\x0e'
+ 0x0F: pC, // '\x0f'
+ 0x10: pC, // '\x10'
+ 0x11: pC, // '\x11'
+ 0x12: pC, // '\x12'
+ 0x13: pC, // '\x13'
+ 0x14: pC, // '\x14'
+ 0x15: pC, // '\x15'
+ 0x16: pC, // '\x16'
+ 0x17: pC, // '\x17'
+ 0x18: pC, // '\x18'
+ 0x19: pC, // '\x19'
+ 0x1A: pC, // '\x1a'
+ 0x1B: pC, // '\x1b'
+ 0x1C: pC, // '\x1c'
+ 0x1D: pC, // '\x1d'
+ 0x1E: pC, // '\x1e'
+ 0x1F: pC, // '\x1f'
+ 0x20: pZ | pp, // ' '
+ 0x21: pP | pp, // '!'
+ 0x22: pP | pp, // '"'
+ 0x23: pP | pp, // '#'
+ 0x24: pS | pp, // '$'
+ 0x25: pP | pp, // '%'
+ 0x26: pP | pp, // '&'
+ 0x27: pP | pp, // '\''
+ 0x28: pP | pp, // '('
+ 0x29: pP | pp, // ')'
+ 0x2A: pP | pp, // '*'
+ 0x2B: pS | pp, // '+'
+ 0x2C: pP | pp, // ','
+ 0x2D: pP | pp, // '-'
+ 0x2E: pP | pp, // '.'
+ 0x2F: pP | pp, // '/'
+ 0x30: pN | pp, // '0'
+ 0x31: pN | pp, // '1'
+ 0x32: pN | pp, // '2'
+ 0x33: pN | pp, // '3'
+ 0x34: pN | pp, // '4'
+ 0x35: pN | pp, // '5'
+ 0x36: pN | pp, // '6'
+ 0x37: pN | pp, // '7'
+ 0x38: pN | pp, // '8'
+ 0x39: pN | pp, // '9'
+ 0x3A: pP | pp, // ':'
+ 0x3B: pP | pp, // ';'
+ 0x3C: pS | pp, // '<'
+ 0x3D: pS | pp, // '='
+ 0x3E: pS | pp, // '>'
+ 0x3F: pP | pp, // '?'
+ 0x40: pP | pp, // '@'
+ 0x41: pLu | pp, // 'A'
+ 0x42: pLu | pp, // 'B'
+ 0x43: pLu | pp, // 'C'
+ 0x44: pLu | pp, // 'D'
+ 0x45: pLu | pp, // 'E'
+ 0x46: pLu | pp, // 'F'
+ 0x47: pLu | pp, // 'G'
+ 0x48: pLu | pp, // 'H'
+ 0x49: pLu | pp, // 'I'
+ 0x4A: pLu | pp, // 'J'
+ 0x4B: pLu | pp, // 'K'
+ 0x4C: pLu | pp, // 'L'
+ 0x4D: pLu | pp, // 'M'
+ 0x4E: pLu | pp, // 'N'
+ 0x4F: pLu | pp, // 'O'
+ 0x50: pLu | pp, // 'P'
+ 0x51: pLu | pp, // 'Q'
+ 0x52: pLu | pp, // 'R'
+ 0x53: pLu | pp, // 'S'
+ 0x54: pLu | pp, // 'T'
+ 0x55: pLu | pp, // 'U'
+ 0x56: pLu | pp, // 'V'
+ 0x57: pLu | pp, // 'W'
+ 0x58: pLu | pp, // 'X'
+ 0x59: pLu | pp, // 'Y'
+ 0x5A: pLu | pp, // 'Z'
+ 0x5B: pP | pp, // '['
+ 0x5C: pP | pp, // '\\'
+ 0x5D: pP | pp, // ']'
+ 0x5E: pS | pp, // '^'
+ 0x5F: pP | pp, // '_'
+ 0x60: pS | pp, // '`'
+ 0x61: pLl | pp, // 'a'
+ 0x62: pLl | pp, // 'b'
+ 0x63: pLl | pp, // 'c'
+ 0x64: pLl | pp, // 'd'
+ 0x65: pLl | pp, // 'e'
+ 0x66: pLl | pp, // 'f'
+ 0x67: pLl | pp, // 'g'
+ 0x68: pLl | pp, // 'h'
+ 0x69: pLl | pp, // 'i'
+ 0x6A: pLl | pp, // 'j'
+ 0x6B: pLl | pp, // 'k'
+ 0x6C: pLl | pp, // 'l'
+ 0x6D: pLl | pp, // 'm'
+ 0x6E: pLl | pp, // 'n'
+ 0x6F: pLl | pp, // 'o'
+ 0x70: pLl | pp, // 'p'
+ 0x71: pLl | pp, // 'q'
+ 0x72: pLl | pp, // 'r'
+ 0x73: pLl | pp, // 's'
+ 0x74: pLl | pp, // 't'
+ 0x75: pLl | pp, // 'u'
+ 0x76: pLl | pp, // 'v'
+ 0x77: pLl | pp, // 'w'
+ 0x78: pLl | pp, // 'x'
+ 0x79: pLl | pp, // 'y'
+ 0x7A: pLl | pp, // 'z'
+ 0x7B: pP | pp, // '{'
+ 0x7C: pS | pp, // '|'
+ 0x7D: pP | pp, // '}'
+ 0x7E: pS | pp, // '~'
+ 0x7F: pC, // '\u007f'
+ 0x80: pC, // '\u0080'
+ 0x81: pC, // '\u0081'
+ 0x82: pC, // '\u0082'
+ 0x83: pC, // '\u0083'
+ 0x84: pC, // '\u0084'
+ 0x85: pC, // '\u0085'
+ 0x86: pC, // '\u0086'
+ 0x87: pC, // '\u0087'
+ 0x88: pC, // '\u0088'
+ 0x89: pC, // '\u0089'
+ 0x8A: pC, // '\u008a'
+ 0x8B: pC, // '\u008b'
+ 0x8C: pC, // '\u008c'
+ 0x8D: pC, // '\u008d'
+ 0x8E: pC, // '\u008e'
+ 0x8F: pC, // '\u008f'
+ 0x90: pC, // '\u0090'
+ 0x91: pC, // '\u0091'
+ 0x92: pC, // '\u0092'
+ 0x93: pC, // '\u0093'
+ 0x94: pC, // '\u0094'
+ 0x95: pC, // '\u0095'
+ 0x96: pC, // '\u0096'
+ 0x97: pC, // '\u0097'
+ 0x98: pC, // '\u0098'
+ 0x99: pC, // '\u0099'
+ 0x9A: pC, // '\u009a'
+ 0x9B: pC, // '\u009b'
+ 0x9C: pC, // '\u009c'
+ 0x9D: pC, // '\u009d'
+ 0x9E: pC, // '\u009e'
+ 0x9F: pC, // '\u009f'
+ 0xA0: pZ, // '\u00a0'
+ 0xA1: pP | pp, // '¡'
+ 0xA2: pS | pp, // '¢'
+ 0xA3: pS | pp, // '£'
+ 0xA4: pS | pp, // '¤'
+ 0xA5: pS | pp, // '¥'
+ 0xA6: pS | pp, // '¦'
+ 0xA7: pS | pp, // '§'
+ 0xA8: pS | pp, // '¨'
+ 0xA9: pS | pp, // '©'
+ 0xAA: pLl | pp, // 'ª'
+ 0xAB: pP | pp, // '«'
+ 0xAC: pS | pp, // '¬'
+ 0xAD: 0, // '\u00ad'
+ 0xAE: pS | pp, // '®'
+ 0xAF: pS | pp, // '¯'
+ 0xB0: pS | pp, // '°'
+ 0xB1: pS | pp, // '±'
+ 0xB2: pN | pp, // '²'
+ 0xB3: pN | pp, // '³'
+ 0xB4: pS | pp, // '´'
+ 0xB5: pLl | pp, // 'µ'
+ 0xB6: pS | pp, // '¶'
+ 0xB7: pP | pp, // '·'
+ 0xB8: pS | pp, // '¸'
+ 0xB9: pN | pp, // '¹'
+ 0xBA: pLl | pp, // 'º'
+ 0xBB: pP | pp, // '»'
+ 0xBC: pN | pp, // '¼'
+ 0xBD: pN | pp, // '½'
+ 0xBE: pN | pp, // '¾'
+ 0xBF: pP | pp, // '¿'
+ 0xC0: pLu | pp, // 'À'
+ 0xC1: pLu | pp, // 'Á'
+ 0xC2: pLu | pp, // 'Â'
+ 0xC3: pLu | pp, // 'Ã'
+ 0xC4: pLu | pp, // 'Ä'
+ 0xC5: pLu | pp, // 'Å'
+ 0xC6: pLu | pp, // 'Æ'
+ 0xC7: pLu | pp, // 'Ç'
+ 0xC8: pLu | pp, // 'È'
+ 0xC9: pLu | pp, // 'É'
+ 0xCA: pLu | pp, // 'Ê'
+ 0xCB: pLu | pp, // 'Ë'
+ 0xCC: pLu | pp, // 'Ì'
+ 0xCD: pLu | pp, // 'Í'
+ 0xCE: pLu | pp, // 'Î'
+ 0xCF: pLu | pp, // 'Ï'
+ 0xD0: pLu | pp, // 'Ð'
+ 0xD1: pLu | pp, // 'Ñ'
+ 0xD2: pLu | pp, // 'Ò'
+ 0xD3: pLu | pp, // 'Ó'
+ 0xD4: pLu | pp, // 'Ô'
+ 0xD5: pLu | pp, // 'Õ'
+ 0xD6: pLu | pp, // 'Ö'
+ 0xD7: pS | pp, // '×'
+ 0xD8: pLu | pp, // 'Ø'
+ 0xD9: pLu | pp, // 'Ù'
+ 0xDA: pLu | pp, // 'Ú'
+ 0xDB: pLu | pp, // 'Û'
+ 0xDC: pLu | pp, // 'Ü'
+ 0xDD: pLu | pp, // 'Ý'
+ 0xDE: pLu | pp, // 'Þ'
+ 0xDF: pLl | pp, // 'ß'
+ 0xE0: pLl | pp, // 'à'
+ 0xE1: pLl | pp, // 'á'
+ 0xE2: pLl | pp, // 'â'
+ 0xE3: pLl | pp, // 'ã'
+ 0xE4: pLl | pp, // 'ä'
+ 0xE5: pLl | pp, // 'å'
+ 0xE6: pLl | pp, // 'æ'
+ 0xE7: pLl | pp, // 'ç'
+ 0xE8: pLl | pp, // 'è'
+ 0xE9: pLl | pp, // 'é'
+ 0xEA: pLl | pp, // 'ê'
+ 0xEB: pLl | pp, // 'ë'
+ 0xEC: pLl | pp, // 'ì'
+ 0xED: pLl | pp, // 'í'
+ 0xEE: pLl | pp, // 'î'
+ 0xEF: pLl | pp, // 'ï'
+ 0xF0: pLl | pp, // 'ð'
+ 0xF1: pLl | pp, // 'ñ'
+ 0xF2: pLl | pp, // 'ò'
+ 0xF3: pLl | pp, // 'ó'
+ 0xF4: pLl | pp, // 'ô'
+ 0xF5: pLl | pp, // 'õ'
+ 0xF6: pLl | pp, // 'ö'
+ 0xF7: pS | pp, // '÷'
+ 0xF8: pLl | pp, // 'ø'
+ 0xF9: pLl | pp, // 'ù'
+ 0xFA: pLl | pp, // 'ú'
+ 0xFB: pLl | pp, // 'û'
+ 0xFC: pLl | pp, // 'ü'
+ 0xFD: pLl | pp, // 'ý'
+ 0xFE: pLl | pp, // 'þ'
+ 0xFF: pLl | pp, // 'ÿ'
+}
+
+var caseOrbit = []foldPair{
+ {0x004B, 0x006B},
+ {0x0053, 0x0073},
+ {0x006B, 0x212A},
+ {0x0073, 0x017F},
+ {0x00B5, 0x039C},
+ {0x00C5, 0x00E5},
+ {0x00DF, 0x1E9E},
+ {0x00E5, 0x212B},
+ {0x0130, 0x0130},
+ {0x0131, 0x0131},
+ {0x017F, 0x0053},
+ {0x01C4, 0x01C5},
+ {0x01C5, 0x01C6},
+ {0x01C6, 0x01C4},
+ {0x01C7, 0x01C8},
+ {0x01C8, 0x01C9},
+ {0x01C9, 0x01C7},
+ {0x01CA, 0x01CB},
+ {0x01CB, 0x01CC},
+ {0x01CC, 0x01CA},
+ {0x01F1, 0x01F2},
+ {0x01F2, 0x01F3},
+ {0x01F3, 0x01F1},
+ {0x0345, 0x0399},
+ {0x0392, 0x03B2},
+ {0x0395, 0x03B5},
+ {0x0398, 0x03B8},
+ {0x0399, 0x03B9},
+ {0x039A, 0x03BA},
+ {0x039C, 0x03BC},
+ {0x03A0, 0x03C0},
+ {0x03A1, 0x03C1},
+ {0x03A3, 0x03C2},
+ {0x03A6, 0x03C6},
+ {0x03A9, 0x03C9},
+ {0x03B2, 0x03D0},
+ {0x03B5, 0x03F5},
+ {0x03B8, 0x03D1},
+ {0x03B9, 0x1FBE},
+ {0x03BA, 0x03F0},
+ {0x03BC, 0x00B5},
+ {0x03C0, 0x03D6},
+ {0x03C1, 0x03F1},
+ {0x03C2, 0x03C3},
+ {0x03C3, 0x03A3},
+ {0x03C6, 0x03D5},
+ {0x03C9, 0x2126},
+ {0x03D0, 0x0392},
+ {0x03D1, 0x03F4},
+ {0x03D5, 0x03A6},
+ {0x03D6, 0x03A0},
+ {0x03F0, 0x039A},
+ {0x03F1, 0x03A1},
+ {0x03F4, 0x0398},
+ {0x03F5, 0x0395},
+ {0x1E60, 0x1E61},
+ {0x1E61, 0x1E9B},
+ {0x1E9B, 0x1E60},
+ {0x1E9E, 0x00DF},
+ {0x1FBE, 0x0345},
+ {0x2126, 0x03A9},
+ {0x212A, 0x004B},
+ {0x212B, 0x00C5},
+}
+
+// FoldCategory maps a category name to a table of
+// code points outside the category that are equivalent under
+// simple case folding to code points inside the category.
+// If there is no entry for a category name, there are no such points.
+var FoldCategory = map[string]*RangeTable{
+ "Ll": foldLl,
+ "Inherited": foldInherited,
+ "M": foldM,
+ "L": foldL,
+ "Mn": foldMn,
+ "Common": foldCommon,
+ "Greek": foldGreek,
+ "Lu": foldLu,
+ "Lt": foldLt,
+}
+
+var foldLl = &RangeTable{
+ R16: []Range16{
+ {0x0041, 0x005a, 1},
+ {0x00c0, 0x00d6, 1},
+ {0x00d8, 0x00de, 1},
+ {0x0100, 0x012e, 2},
+ {0x0132, 0x0136, 2},
+ {0x0139, 0x0147, 2},
+ {0x014a, 0x0178, 2},
+ {0x0179, 0x017d, 2},
+ {0x0181, 0x0182, 1},
+ {0x0184, 0x0186, 2},
+ {0x0187, 0x0189, 2},
+ {0x018a, 0x018b, 1},
+ {0x018e, 0x0191, 1},
+ {0x0193, 0x0194, 1},
+ {0x0196, 0x0198, 1},
+ {0x019c, 0x019d, 1},
+ {0x019f, 0x01a0, 1},
+ {0x01a2, 0x01a6, 2},
+ {0x01a7, 0x01a9, 2},
+ {0x01ac, 0x01ae, 2},
+ {0x01af, 0x01b1, 2},
+ {0x01b2, 0x01b3, 1},
+ {0x01b5, 0x01b7, 2},
+ {0x01b8, 0x01bc, 4},
+ {0x01c4, 0x01c5, 1},
+ {0x01c7, 0x01c8, 1},
+ {0x01ca, 0x01cb, 1},
+ {0x01cd, 0x01db, 2},
+ {0x01de, 0x01ee, 2},
+ {0x01f1, 0x01f2, 1},
+ {0x01f4, 0x01f6, 2},
+ {0x01f7, 0x01f8, 1},
+ {0x01fa, 0x0232, 2},
+ {0x023a, 0x023b, 1},
+ {0x023d, 0x023e, 1},
+ {0x0241, 0x0243, 2},
+ {0x0244, 0x0246, 1},
+ {0x0248, 0x024e, 2},
+ {0x0345, 0x0370, 43},
+ {0x0372, 0x0376, 4},
+ {0x0386, 0x0388, 2},
+ {0x0389, 0x038a, 1},
+ {0x038c, 0x038e, 2},
+ {0x038f, 0x0391, 2},
+ {0x0392, 0x03a1, 1},
+ {0x03a3, 0x03ab, 1},
+ {0x03cf, 0x03d8, 9},
+ {0x03da, 0x03ee, 2},
+ {0x03f4, 0x03f7, 3},
+ {0x03f9, 0x03fa, 1},
+ {0x03fd, 0x042f, 1},
+ {0x0460, 0x0480, 2},
+ {0x048a, 0x04c0, 2},
+ {0x04c1, 0x04cd, 2},
+ {0x04d0, 0x0526, 2},
+ {0x0531, 0x0556, 1},
+ {0x10a0, 0x10c5, 1},
+ {0x1e00, 0x1e94, 2},
+ {0x1e9e, 0x1efe, 2},
+ {0x1f08, 0x1f0f, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f28, 0x1f2f, 1},
+ {0x1f38, 0x1f3f, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f68, 0x1f6f, 1},
+ {0x1f88, 0x1f8f, 1},
+ {0x1f98, 0x1f9f, 1},
+ {0x1fa8, 0x1faf, 1},
+ {0x1fb8, 0x1fbc, 1},
+ {0x1fc8, 0x1fcc, 1},
+ {0x1fd8, 0x1fdb, 1},
+ {0x1fe8, 0x1fec, 1},
+ {0x1ff8, 0x1ffc, 1},
+ {0x2126, 0x212a, 4},
+ {0x212b, 0x2132, 7},
+ {0x2183, 0x2c00, 2685},
+ {0x2c01, 0x2c2e, 1},
+ {0x2c60, 0x2c62, 2},
+ {0x2c63, 0x2c64, 1},
+ {0x2c67, 0x2c6d, 2},
+ {0x2c6e, 0x2c70, 1},
+ {0x2c72, 0x2c75, 3},
+ {0x2c7e, 0x2c80, 1},
+ {0x2c82, 0x2ce2, 2},
+ {0x2ceb, 0x2ced, 2},
+ {0xa640, 0xa66c, 2},
+ {0xa680, 0xa696, 2},
+ {0xa722, 0xa72e, 2},
+ {0xa732, 0xa76e, 2},
+ {0xa779, 0xa77d, 2},
+ {0xa77e, 0xa786, 2},
+ {0xa78b, 0xa78d, 2},
+ {0xa790, 0xa7a0, 16},
+ {0xa7a2, 0xa7a8, 2},
+ {0xff21, 0xff3a, 1},
+ },
+ R32: []Range32{
+ {0x10400, 0x10427, 1},
+ },
+}
+
+var foldInherited = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldM = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldL = &RangeTable{
+ R16: []Range16{
+ {0x0345, 0x0345, 1},
+ },
+}
+
+var foldMn = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldCommon = &RangeTable{
+ R16: []Range16{
+ {0x039c, 0x03bc, 32},
+ },
+}
+
+var foldGreek = &RangeTable{
+ R16: []Range16{
+ {0x00b5, 0x0345, 656},
+ },
+}
+
+var foldLu = &RangeTable{
+ R16: []Range16{
+ {0x0061, 0x007a, 1},
+ {0x00b5, 0x00df, 42},
+ {0x00e0, 0x00f6, 1},
+ {0x00f8, 0x00ff, 1},
+ {0x0101, 0x012f, 2},
+ {0x0133, 0x0137, 2},
+ {0x013a, 0x0148, 2},
+ {0x014b, 0x0177, 2},
+ {0x017a, 0x017e, 2},
+ {0x017f, 0x0180, 1},
+ {0x0183, 0x0185, 2},
+ {0x0188, 0x018c, 4},
+ {0x0192, 0x0195, 3},
+ {0x0199, 0x019a, 1},
+ {0x019e, 0x01a1, 3},
+ {0x01a3, 0x01a5, 2},
+ {0x01a8, 0x01ad, 5},
+ {0x01b0, 0x01b4, 4},
+ {0x01b6, 0x01b9, 3},
+ {0x01bd, 0x01bf, 2},
+ {0x01c5, 0x01c6, 1},
+ {0x01c8, 0x01c9, 1},
+ {0x01cb, 0x01cc, 1},
+ {0x01ce, 0x01dc, 2},
+ {0x01dd, 0x01ef, 2},
+ {0x01f2, 0x01f3, 1},
+ {0x01f5, 0x01f9, 4},
+ {0x01fb, 0x021f, 2},
+ {0x0223, 0x0233, 2},
+ {0x023c, 0x023f, 3},
+ {0x0240, 0x0242, 2},
+ {0x0247, 0x024f, 2},
+ {0x0250, 0x0254, 1},
+ {0x0256, 0x0257, 1},
+ {0x0259, 0x025b, 2},
+ {0x0260, 0x0263, 3},
+ {0x0265, 0x0268, 3},
+ {0x0269, 0x026b, 2},
+ {0x026f, 0x0271, 2},
+ {0x0272, 0x0275, 3},
+ {0x027d, 0x0283, 3},
+ {0x0288, 0x028c, 1},
+ {0x0292, 0x0345, 179},
+ {0x0371, 0x0373, 2},
+ {0x0377, 0x037b, 4},
+ {0x037c, 0x037d, 1},
+ {0x03ac, 0x03af, 1},
+ {0x03b1, 0x03ce, 1},
+ {0x03d0, 0x03d1, 1},
+ {0x03d5, 0x03d7, 1},
+ {0x03d9, 0x03ef, 2},
+ {0x03f0, 0x03f2, 1},
+ {0x03f5, 0x03fb, 3},
+ {0x0430, 0x045f, 1},
+ {0x0461, 0x0481, 2},
+ {0x048b, 0x04bf, 2},
+ {0x04c2, 0x04ce, 2},
+ {0x04cf, 0x0527, 2},
+ {0x0561, 0x0586, 1},
+ {0x1d79, 0x1d7d, 4},
+ {0x1e01, 0x1e95, 2},
+ {0x1e9b, 0x1ea1, 6},
+ {0x1ea3, 0x1eff, 2},
+ {0x1f00, 0x1f07, 1},
+ {0x1f10, 0x1f15, 1},
+ {0x1f20, 0x1f27, 1},
+ {0x1f30, 0x1f37, 1},
+ {0x1f40, 0x1f45, 1},
+ {0x1f51, 0x1f57, 2},
+ {0x1f60, 0x1f67, 1},
+ {0x1f70, 0x1f7d, 1},
+ {0x1fb0, 0x1fb1, 1},
+ {0x1fbe, 0x1fd0, 18},
+ {0x1fd1, 0x1fe0, 15},
+ {0x1fe1, 0x1fe5, 4},
+ {0x214e, 0x2184, 54},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c61, 0x2c65, 4},
+ {0x2c66, 0x2c6c, 2},
+ {0x2c73, 0x2c76, 3},
+ {0x2c81, 0x2ce3, 2},
+ {0x2cec, 0x2cee, 2},
+ {0x2d00, 0x2d25, 1},
+ {0xa641, 0xa66d, 2},
+ {0xa681, 0xa697, 2},
+ {0xa723, 0xa72f, 2},
+ {0xa733, 0xa76f, 2},
+ {0xa77a, 0xa77c, 2},
+ {0xa77f, 0xa787, 2},
+ {0xa78c, 0xa791, 5},
+ {0xa7a1, 0xa7a9, 2},
+ {0xff41, 0xff5a, 1},
+ },
+ R32: []Range32{
+ {0x10428, 0x1044f, 1},
+ },
+}
+
+var foldLt = &RangeTable{
+ R16: []Range16{
+ {0x01c4, 0x01c6, 2},
+ {0x01c7, 0x01c9, 2},
+ {0x01ca, 0x01cc, 2},
+ {0x01f1, 0x01f3, 2},
+ {0x1f80, 0x1f87, 1},
+ {0x1f90, 0x1f97, 1},
+ {0x1fa0, 0x1fa7, 1},
+ {0x1fb3, 0x1fc3, 16},
+ {0x1ff3, 0x1ff3, 1},
+ },
+}
+
+// FoldScript maps a script name to a table of
+// code points outside the script that are equivalent under
+// simple case folding to code points inside the script.
+// If there is no entry for a script name, there are no such points.
+var FoldScript = map[string]*RangeTable{}
+
+// Range entries: 3391 16-bit, 659 32-bit, 4050 total.
+// Range bytes: 20346 16-bit, 7908 32-bit, 28254 total.
+
+// Fold orbit bytes: 63 pairs, 252 bytes
diff --git a/libgo/go/http/url.go b/libgo/go/url/url.go
index d7ee14ee84a..d07b016118f 100644
--- a/libgo/go/http/url.go
+++ b/libgo/go/url/url.go
@@ -2,10 +2,9 @@
// 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
+// Package URL parses URLs and implements query escaping.
+// See RFC 3986.
+package url
import (
"os"
@@ -13,14 +12,14 @@ import (
"strings"
)
-// URLError reports an error and the operation and URL that caused it.
-type URLError struct {
+// Error reports an error and the operation and URL that caused it.
+type Error struct {
Op string
URL string
Error os.Error
}
-func (e *URLError) String() string { return e.Op + " " + e.URL + ": " + e.Error.String() }
+func (e *Error) String() string { return e.Op + " " + e.URL + ": " + e.Error.String() }
func ishex(c byte) bool {
switch {
@@ -56,10 +55,9 @@ const (
encodeOpaque
)
+type EscapeError string
-type URLEscapeError string
-
-func (e URLEscapeError) String() string {
+func (e EscapeError) String() string {
return "invalid URL escape " + strconv.Quote(string(e))
}
@@ -114,20 +112,16 @@ func shouldEscape(c byte, mode encoding) bool {
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)
+// QueryUnescape does the inverse transformation of QueryEscape, converting
+// %AB into the byte 0xAB and '+' into ' ' (space). It returns an error if
+// any % is not followed by two hexadecimal digits.
+func QueryUnescape(s string) (string, os.Error) {
+ return unescape(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) {
+// unescape unescapes a string; the mode specifies
+// which section of the URL string is being unescaped.
+func unescape(s string, mode encoding) (string, os.Error) {
// Count %, check that they're well-formed.
n := 0
hasPlus := false
@@ -140,7 +134,7 @@ func urlUnescape(s string, mode encoding) (string, os.Error) {
if len(s) > 3 {
s = s[0:3]
}
- return "", URLEscapeError(s)
+ return "", EscapeError(s)
}
i += 3
case '+':
@@ -180,14 +174,13 @@ func urlUnescape(s string, mode encoding) (string, os.Error) {
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)
+// QueryEscape escapes the string so it can be safely placed
+// inside a URL query.
+func QueryEscape(s string) string {
+ return escape(s, encodeQueryComponent)
}
-func urlEscape(s string, mode encoding) string {
+func escape(s string, mode encoding) string {
spaceCount, hexCount := 0, 0
for i := 0; i < len(s); i++ {
c := s[i]
@@ -235,10 +228,10 @@ func urlEscape(s string, mode encoding) string {
// 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 {
+ if user, err = unescape(u, encodeUserPassword); err != nil {
return "", "", err
}
- if password, err = urlUnescape(p, encodeUserPassword); err != nil {
+ if password, err = unescape(p, encodeUserPassword); err != nil {
return "", "", err
}
return
@@ -254,9 +247,9 @@ func UnescapeUserinfo(rawUserinfo string) (user, password string, err os.Error)
// 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)
+ raw := escape(user, encodeUserPassword)
if password != "" {
- raw += ":" + urlEscape(password, encodeUserPassword)
+ raw += ":" + escape(password, encodeUserPassword)
}
return raw
}
@@ -299,7 +292,7 @@ func getscheme(rawurl string) (scheme, path string, err os.Error) {
}
case c == ':':
if i == 0 {
- return "", "", os.ErrorString("missing protocol scheme")
+ return "", "", os.NewError("missing protocol scheme")
}
return rawurl[0:i], rawurl[i+1:], nil
default:
@@ -326,30 +319,35 @@ func split(s string, c byte, cutc bool) (string, string) {
return s, ""
}
-// ParseURL parses rawurl into a URL structure.
+// Parse 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)
+func Parse(rawurl string) (url *URL, err os.Error) {
+ return parse(rawurl, false)
}
-// ParseRequestURL parses rawurl into a URL structure. It assumes that
+// ParseRequest 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)
+func ParseRequest(rawurl string) (url *URL, err os.Error) {
+ return parse(rawurl, true)
}
-// parseURL parses a URL from a string in one of two contexts. If
+// parse 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) {
+func parse(rawurl string, viaRequest bool) (url *URL, err os.Error) {
+ var (
+ leadingSlash bool
+ path string
+ )
+
if rawurl == "" {
- err = os.ErrorString("empty url")
+ err = os.NewError("empty url")
goto Error
}
url = new(URL)
@@ -357,12 +355,10 @@ func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) {
// Split off possible leading "http:", "mailto:", etc.
// Cannot contain escaped characters.
- var path string
if url.Scheme, path, err = getscheme(rawurl); err != nil {
goto Error
}
-
- leadingSlash := strings.HasPrefix(path, "/")
+ leadingSlash = strings.HasPrefix(path, "/")
if url.Scheme != "" && !leadingSlash {
// RFC 2396:
@@ -371,13 +367,13 @@ func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) {
// This is the case that handles mailto:name@example.com.
url.RawPath = path
- if url.Path, err = urlUnescape(path, encodeOpaque); err != nil {
+ if url.Path, err = unescape(path, encodeOpaque); err != nil {
goto Error
}
url.OpaquePath = true
} else {
if viaRequest && !leadingSlash {
- err = os.ErrorString("invalid URI for request")
+ err = os.NewError("invalid URI for request")
goto Error
}
@@ -411,35 +407,35 @@ func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) {
if strings.Contains(rawHost, "%") {
// Host cannot contain escaped characters.
- err = os.ErrorString("hexadecimal escape in host")
+ err = os.NewError("hexadecimal escape in host")
goto Error
}
url.Host = rawHost
- if url.Path, err = urlUnescape(path, encodePath); err != nil {
+ if url.Path, err = unescape(path, encodePath); err != nil {
goto Error
}
}
return url, nil
Error:
- return nil, &URLError{"parse", rawurl, err}
+ return nil, &Error{"parse", rawurl, err}
}
-// ParseURLReference is like ParseURL but allows a trailing #fragment.
-func ParseURLReference(rawurlref string) (url *URL, err os.Error) {
+// ParseWithReference is like Parse but allows a trailing #fragment.
+func ParseWithReference(rawurlref string) (url *URL, err os.Error) {
// Cut off #frag.
rawurl, frag := split(rawurlref, '#', false)
- if url, err = ParseURL(rawurl); err != nil {
+ if url, err = Parse(rawurl); err != nil {
return nil, err
}
url.Raw += frag
url.RawPath += frag
if len(frag) > 1 {
frag = frag[1:]
- if url.Fragment, err = urlUnescape(frag, encodeFragment); err != nil {
- return nil, &URLError{"parse", rawurl, err}
+ if url.Fragment, err = unescape(frag, encodeFragment); err != nil {
+ return nil, &Error{"parse", rawurl, err}
}
}
return url, nil
@@ -473,26 +469,101 @@ func (url *URL) String() string {
result += "%2f"
path = path[1:]
}
- result += urlEscape(path, encodeOpaque)
+ result += escape(path, encodeOpaque)
} else {
- result += urlEscape(url.Path, encodePath)
+ result += escape(url.Path, encodePath)
}
if url.RawQuery != "" {
result += "?" + url.RawQuery
}
if url.Fragment != "" {
- result += "#" + urlEscape(url.Fragment, encodeFragment)
+ result += "#" + escape(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) + "="
+// Values maps a string key to a list of values.
+// It is typically used for query parameters and form values.
+// Unlike in the http.Header map, the keys in a Values map
+// are case-sensitive.
+type Values map[string][]string
+
+// Get gets the first value associated with the given key.
+// If there are no values associated with the key, Get returns
+// the empty string. To access multiple values, use the map
+// directly.
+func (v Values) Get(key string) string {
+ if v == nil {
+ return ""
+ }
+ vs, ok := v[key]
+ if !ok || len(vs) == 0 {
+ return ""
+ }
+ return vs[0]
+}
+
+// Set sets the key to value. It replaces any existing
+// values.
+func (v Values) Set(key, value string) {
+ v[key] = []string{value}
+}
+
+// Add adds the key to value. It appends to any existing
+// values associated with key.
+func (v Values) Add(key, value string) {
+ v[key] = append(v[key], value)
+}
+
+// Del deletes the values associated with key.
+func (v Values) Del(key string) {
+ v[key] = nil, false
+}
+
+// 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 Values, err os.Error) {
+ m = make(Values)
+ err = parseQuery(m, query)
+ return
+}
+
+func parseQuery(m Values, query string) (err os.Error) {
+ for _, kv := range strings.Split(query, "&") {
+ if len(kv) == 0 {
+ continue
+ }
+ kvPair := strings.SplitN(kv, "=", 2)
+
+ var key, value string
+ var e os.Error
+ key, e = QueryUnescape(kvPair[0])
+ if e == nil && len(kvPair) > 1 {
+ value, e = QueryUnescape(kvPair[1])
+ }
+ if e != nil {
+ err = e
+ continue
+ }
+ m[key] = append(m[key], value)
+ }
+ return err
+}
+
+// Encode encodes the values into ``URL encoded'' form.
+// e.g. "foo=bar&bar=baz"
+func (v Values) Encode() string {
+ if v == nil {
+ return ""
+ }
+ parts := make([]string, 0, len(v)) // will be large enough for most uses
+ for k, vs := range v {
+ prefix := QueryEscape(k) + "="
for _, v := range vs {
- parts = append(parts, prefix+URLEscape(v))
+ parts = append(parts, prefix+QueryEscape(v))
}
}
return strings.Join(parts, "&")
@@ -501,8 +572,8 @@ func EncodeQuery(m map[string][]string) string {
// 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)
+ base := strings.Split(basepath, "/")
+ refs := strings.Split(refpath, "/")
if len(base) == 0 {
base = []string{""}
}
@@ -533,11 +604,11 @@ 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
+// Parse parses a URL in the context of a base URL. The URL in ref
+// may be relative or absolute. Parse 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)
+func (base *URL) Parse(ref string) (*URL, os.Error) {
+ refurl, err := Parse(ref)
if err != nil {
return nil, err
}
@@ -593,3 +664,14 @@ func (base *URL) ResolveReference(ref *URL) *URL {
url.Raw = url.String()
return url
}
+
+// Query parses RawQuery and returns the corresponding values.
+func (u *URL) Query() Values {
+ v, _ := ParseQuery(u.RawQuery)
+ return v
+}
+
+// EncodedPath returns the URL's path in "URL path encoded" form.
+func (u *URL) EncodedPath() string {
+ return escape(u.Path, encodePath)
+}
diff --git a/libgo/go/http/url_test.go b/libgo/go/url/url_test.go
index d8863f3d3b5..af394d4fb4a 100644
--- a/libgo/go/http/url_test.go
+++ b/libgo/go/url/url_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package http
+package url
import (
"fmt"
@@ -12,9 +12,9 @@ import (
)
// TODO(rsc):
-// test URLUnescape
-// test URLEscape
-// test ParseURL
+// test Unescape
+// test Escape
+// test Parse
type URLTest struct {
in string
@@ -218,7 +218,7 @@ var urltests = []URLTest{
},
// 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
+ // ServeHTTP -> ReadRequest -> Parse, which is arguably a
// different URL parsing context, but currently shares the
// same codepath)
{
@@ -325,14 +325,14 @@ func DoTest(t *testing.T, parse func(string) (*URL, os.Error), name string, test
}
}
-func TestParseURL(t *testing.T) {
- DoTest(t, ParseURL, "ParseURL", urltests)
- DoTest(t, ParseURL, "ParseURL", urlnofragtests)
+func TestParse(t *testing.T) {
+ DoTest(t, Parse, "Parse", urltests)
+ DoTest(t, Parse, "Parse", urlnofragtests)
}
-func TestParseURLReference(t *testing.T) {
- DoTest(t, ParseURLReference, "ParseURLReference", urltests)
- DoTest(t, ParseURLReference, "ParseURLReference", urlfragtests)
+func TestParseWithReference(t *testing.T) {
+ DoTest(t, ParseWithReference, "ParseWithReference", urltests)
+ DoTest(t, ParseWithReference, "ParseWithReference", urlfragtests)
}
const pathThatLooksSchemeRelative = "//not.a.user@not.a.host/just/a/path"
@@ -351,16 +351,16 @@ var parseRequestUrlTests = []struct {
{"../dir/", false},
}
-func TestParseRequestURL(t *testing.T) {
+func TestParseRequest(t *testing.T) {
for _, test := range parseRequestUrlTests {
- _, err := ParseRequestURL(test.url)
+ _, err := ParseRequest(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)
+ url, err := ParseRequest(pathThatLooksSchemeRelative)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
@@ -388,19 +388,19 @@ func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string
}
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)
+ DoTestString(t, Parse, "Parse", urltests)
+ DoTestString(t, Parse, "Parse", urlnofragtests)
+ DoTestString(t, ParseWithReference, "ParseWithReference", urltests)
+ DoTestString(t, ParseWithReference, "ParseWithReference", urlfragtests)
}
-type URLEscapeTest struct {
+type EscapeTest struct {
in string
out string
err os.Error
}
-var unescapeTests = []URLEscapeTest{
+var unescapeTests = []EscapeTest{
{
"",
"",
@@ -434,40 +434,40 @@ var unescapeTests = []URLEscapeTest{
{
"%", // not enough characters after %
"",
- URLEscapeError("%"),
+ EscapeError("%"),
},
{
"%a", // not enough characters after %
"",
- URLEscapeError("%a"),
+ EscapeError("%a"),
},
{
"%1", // not enough characters after %
"",
- URLEscapeError("%1"),
+ EscapeError("%1"),
},
{
"123%45%6", // not enough characters after %
"",
- URLEscapeError("%6"),
+ EscapeError("%6"),
},
{
"%zzzzz", // invalid hex digits
"",
- URLEscapeError("%zz"),
+ EscapeError("%zz"),
},
}
-func TestURLUnescape(t *testing.T) {
+func TestUnescape(t *testing.T) {
for _, tt := range unescapeTests {
- actual, err := URLUnescape(tt.in)
+ actual, err := QueryUnescape(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)
+ t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", tt.in, actual, err, tt.out, tt.err)
}
}
}
-var escapeTests = []URLEscapeTest{
+var escapeTests = []EscapeTest{
{
"",
"",
@@ -495,17 +495,17 @@ var escapeTests = []URLEscapeTest{
},
}
-func TestURLEscape(t *testing.T) {
+func TestEscape(t *testing.T) {
for _, tt := range escapeTests {
- actual := URLEscape(tt.in)
+ actual := QueryEscape(tt.in)
if tt.out != actual {
- t.Errorf("URLEscape(%q) = %q, want %q", tt.in, actual, tt.out)
+ t.Errorf("QueryEscape(%q) = %q, want %q", tt.in, actual, tt.out)
}
// for bonus points, verify that escape:unescape is an identity.
- roundtrip, err := URLUnescape(actual)
+ roundtrip, err := QueryUnescape(actual)
if roundtrip != tt.in || err != nil {
- t.Errorf("URLUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
+ t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
}
}
}
@@ -538,23 +538,21 @@ func TestUnescapeUserinfo(t *testing.T) {
}
}
-type qMap map[string][]string
-
type EncodeQueryTest struct {
- m qMap
+ m Values
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"},
+ {Values{"q": {"puppies"}, "oe": {"utf8"}}, "q=puppies&oe=utf8", "oe=utf8&q=puppies"},
+ {Values{"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 {
+ if q := tt.m.Encode(); q != tt.expected && q != tt.expected1 {
t.Errorf(`EncodeQuery(%+v) = %q, want %q`, tt.m, q, tt.expected)
}
}
@@ -631,16 +629,16 @@ var resolveReferenceTests = []struct {
}
func TestResolveReference(t *testing.T) {
- mustParseURL := func(url string) *URL {
- u, err := ParseURLReference(url)
+ mustParse := func(url string) *URL {
+ u, err := ParseWithReference(url)
if err != nil {
t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
}
return u
}
for _, test := range resolveReferenceTests {
- base := mustParseURL(test.base)
- rel := mustParseURL(test.rel)
+ base := mustParse(test.base)
+ rel := mustParse(test.rel)
url := base.ResolveReference(rel)
urlStr := url.String()
if urlStr != test.expected {
@@ -649,27 +647,52 @@ func TestResolveReference(t *testing.T) {
}
// Test that new instances are returned.
- base := mustParseURL("http://foo.com/")
- abs := base.ResolveReference(mustParseURL("."))
+ base := mustParse("http://foo.com/")
+ abs := base.ResolveReference(mustParse("."))
if base == abs {
t.Errorf("Expected no-op reference to return new URL instance.")
}
- barRef := mustParseURL("http://bar.com/")
+ barRef := mustParse("http://bar.com/")
abs = base.ResolveReference(barRef)
if abs == barRef {
t.Errorf("Expected resolution of absolute reference to return new URL instance.")
}
// Test the convenience wrapper too
- base = mustParseURL("http://foo.com/path/one/")
- abs, _ = base.ParseURL("../two")
+ base = mustParse("http://foo.com/path/one/")
+ abs, _ = base.Parse("../two")
expected := "http://foo.com/path/two"
if abs.String() != expected {
- t.Errorf("ParseURL wrapper got %q; expected %q", abs.String(), expected)
+ t.Errorf("Parse wrapper got %q; expected %q", abs.String(), expected)
}
- _, err := base.ParseURL("")
+ _, err := base.Parse("")
if err == nil {
- t.Errorf("Expected an error from ParseURL wrapper parsing an empty string.")
+ t.Errorf("Expected an error from Parse wrapper parsing an empty string.")
}
}
+
+func TestQueryValues(t *testing.T) {
+ u, _ := Parse("http://x.com?foo=bar&bar=1&bar=2")
+ v := u.Query()
+ if len(v) != 2 {
+ t.Errorf("got %d keys in Query values, want 2", len(v))
+ }
+ if g, e := v.Get("foo"), "bar"; g != e {
+ t.Errorf("Get(foo) = %q, want %q", g, e)
+ }
+ // Case sensitive:
+ if g, e := v.Get("Foo"), ""; g != e {
+ t.Errorf("Get(Foo) = %q, want %q", g, e)
+ }
+ if g, e := v.Get("bar"), "1"; g != e {
+ t.Errorf("Get(bar) = %q, want %q", g, e)
+ }
+ if g, e := v.Get("baz"), ""; g != e {
+ t.Errorf("Get(baz) = %q, want %q", g, e)
+ }
+ v.Del("bar")
+ if g, e := v.Get("bar"), ""; g != e {
+ t.Errorf("second Get(bar) = %q, want %q", g, e)
+ }
+}
diff --git a/libgo/go/utf8/utf8.go b/libgo/go/utf8/utf8.go
index f542358d6dc..8910e17d770 100644
--- a/libgo/go/utf8/utf8.go
+++ b/libgo/go/utf8/utf8.go
@@ -16,22 +16,22 @@ const (
)
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
+ 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) {
@@ -42,12 +42,12 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
c0 := p[0]
// 1-byte, 7-bit sequence?
- if c0 < _Tx {
+ if c0 < tx {
return int(c0), 1, false
}
// unexpected continuation byte?
- if c0 < _T2 {
+ if c0 < t2 {
return RuneError, 1, false
}
@@ -56,14 +56,14 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
return RuneError, 1, true
}
c1 := p[1]
- if c1 < _Tx || _T2 <= c1 {
+ 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 {
+ if c0 < t3 {
+ rune = int(c0&mask2)<<6 | int(c1&maskx)
+ if rune <= rune1Max {
return RuneError, 1, false
}
return rune, 2, false
@@ -74,14 +74,14 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
return RuneError, 1, true
}
c2 := p[2]
- if c2 < _Tx || _T2 <= c2 {
+ 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 {
+ 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
@@ -92,14 +92,14 @@ func decodeRuneInternal(p []byte) (rune, size int, short bool) {
return RuneError, 1, true
}
c3 := p[3]
- if c3 < _Tx || _T2 <= c3 {
+ 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 {
+ 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
@@ -117,12 +117,12 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
c0 := s[0]
// 1-byte, 7-bit sequence?
- if c0 < _Tx {
+ if c0 < tx {
return int(c0), 1, false
}
// unexpected continuation byte?
- if c0 < _T2 {
+ if c0 < t2 {
return RuneError, 1, false
}
@@ -131,14 +131,14 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
return RuneError, 1, true
}
c1 := s[1]
- if c1 < _Tx || _T2 <= c1 {
+ 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 {
+ if c0 < t3 {
+ rune = int(c0&mask2)<<6 | int(c1&maskx)
+ if rune <= rune1Max {
return RuneError, 1, false
}
return rune, 2, false
@@ -149,14 +149,14 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
return RuneError, 1, true
}
c2 := s[2]
- if c2 < _Tx || _T2 <= c2 {
+ 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 {
+ 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
@@ -167,14 +167,14 @@ func decodeRuneInStringInternal(s string) (rune, size int, short bool) {
return RuneError, 1, true
}
c3 := s[3]
- if c3 < _Tx || _T2 <= c3 {
+ 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 {
+ 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
@@ -279,13 +279,13 @@ func DecodeLastRuneInString(s string) (rune, size int) {
// RuneLen returns the number of bytes required to encode the rune.
func RuneLen(rune int) int {
switch {
- case rune <= _Rune1Max:
+ case rune <= rune1Max:
return 1
- case rune <= _Rune2Max:
+ case rune <= rune2Max:
return 2
- case rune <= _Rune3Max:
+ case rune <= rune3Max:
return 3
- case rune <= _Rune4Max:
+ case rune <= rune4Max:
return 4
}
return -1
@@ -297,14 +297,14 @@ func EncodeRune(p []byte, rune int) int {
// Negative values are erroneous. Making it unsigned addresses the problem.
r := uint(rune)
- if r <= _Rune1Max {
+ if r <= rune1Max {
p[0] = byte(r)
return 1
}
- if r <= _Rune2Max {
- p[0] = _T2 | byte(r>>6)
- p[1] = _Tx | byte(r)&_Maskx
+ if r <= rune2Max {
+ p[0] = t2 | byte(r>>6)
+ p[1] = tx | byte(r)&maskx
return 2
}
@@ -312,17 +312,17 @@ func EncodeRune(p []byte, rune int) int {
r = RuneError
}
- if r <= _Rune3Max {
- p[0] = _T3 | byte(r>>12)
- p[1] = _Tx | byte(r>>6)&_Maskx
- p[2] = _Tx | byte(r)&_Maskx
+ 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
+ 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
}
diff --git a/libgo/go/websocket/client.go b/libgo/go/websocket/client.go
index 78c8b7f57bf..74bede4249f 100644
--- a/libgo/go/websocket/client.go
+++ b/libgo/go/websocket/client.go
@@ -7,7 +7,6 @@ package websocket
import (
"bufio"
"bytes"
- "container/vector"
"crypto/tls"
"fmt"
"http"
@@ -16,20 +15,23 @@ import (
"os"
"rand"
"strings"
+ "url"
)
type ProtocolError struct {
- os.ErrorString
+ ErrorString string
}
+func (err *ProtocolError) String() string { return string(err.ErrorString) }
+
var (
- ErrBadScheme = os.ErrorString("bad scheme")
+ ErrBadScheme = &ProtocolError{"bad scheme"}
ErrBadStatus = &ProtocolError{"bad status"}
ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
- ErrChallengeResponse = &ProtocolError{"mismatch challange/response"}
+ ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"}
secKeyRandomChars [0x30 - 0x21 + 0x7F - 0x3A]byte
)
@@ -98,10 +100,10 @@ A trivial example client:
// use msg[0:n]
}
*/
-func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
+func Dial(url_, protocol, origin string) (ws *Conn, err os.Error) {
var client net.Conn
- parsedUrl, err := http.ParseURL(url)
+ parsedUrl, err := url.Parse(url_)
if err != nil {
goto Error
}
@@ -120,14 +122,14 @@ func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
goto Error
}
- ws, err = newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url, protocol, client, handshake)
+ 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}
+ return nil, &DialError{url_, protocol, origin, err}
}
/*
@@ -199,21 +201,21 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
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")
+ var fields []string
+ fields = append(fields, "Upgrade: WebSocket\r\n")
+ fields = append(fields, "Connection: Upgrade\r\n")
+ fields = append(fields, "Host: "+host+"\r\n")
+ fields = append(fields, "Origin: "+origin+"\r\n")
if protocol != "" {
- fields.Push("Sec-WebSocket-Protocol: " + protocol + "\r\n")
+ fields = append(fields, "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")
+ fields = append(fields, "Sec-WebSocket-Key1: "+key1+"\r\n")
+ fields = append(fields, "Sec-WebSocket-Key2: "+key2+"\r\n")
// Step 24. shuffle fields and send them out.
for i := 1; i < len(fields); i++ {
@@ -226,7 +228,7 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
// Step 25. send CRLF.
bw.WriteString("\r\n")
- // Step 26. genearte 8 bytes random key.
+ // Step 26. generate 8 bytes random key.
key3 := generateKey3()
// Step 27. send it out.
bw.Write(key3)
@@ -235,7 +237,7 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
}
// Step 28-29, 32-40. read response from server.
- resp, err := http.ReadResponse(br, "GET")
+ resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
if err != nil {
return err
}
@@ -262,7 +264,7 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
return ErrBadWebSocketProtocol
}
- // Step 42-43. get expected data from challange data.
+ // Step 42-43. get expected data from challenge data.
expected, err := getChallengeResponse(number1, number2, key3)
if err != nil {
return err
@@ -283,7 +285,7 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
}
/*
-Handhake described in (soon obsolete)
+Handshake 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) {
@@ -297,7 +299,7 @@ func draft75handshake(resourceName, host, origin, location, protocol string, br
}
bw.WriteString("\r\n")
bw.Flush()
- resp, err := http.ReadResponse(br, "GET")
+ resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
if err != nil {
return
}
diff --git a/libgo/go/websocket/server.go b/libgo/go/websocket/server.go
index 376265236e2..e0e7c872db4 100644
--- a/libgo/go/websocket/server.go
+++ b/libgo/go/websocket/server.go
@@ -124,7 +124,7 @@ func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
part1 := keyNumber1 / space1
part2 := keyNumber2 / space2
- // Step 8. let challenge to be concatination of part1, part2 and key3.
+ // Step 8. let challenge be concatenation of part1, part2 and key3.
// Step 9. get MD5 fingerprint of challenge.
response, err := getChallengeResponse(part1, part2, key3)
if err != nil {
@@ -154,7 +154,6 @@ func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
f(ws)
}
-
/*
Draft75Handler is an interface to a WebSocket based on the
(soon obsolete) draft-hixie-thewebsocketprotocol-75.
diff --git a/libgo/go/websocket/websocket.go b/libgo/go/websocket/websocket.go
index edde61b4a76..7447cf85215 100644
--- a/libgo/go/websocket/websocket.go
+++ b/libgo/go/websocket/websocket.go
@@ -158,7 +158,7 @@ func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
return os.EINVAL
}
-// SetWritetTimeout sets the connection's network write timeout in nanoseconds.
+// SetWriteTimeout 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)
diff --git a/libgo/go/websocket/websocket_test.go b/libgo/go/websocket/websocket_test.go
index 10f88dfd1a0..71c3c8514b7 100644
--- a/libgo/go/websocket/websocket_test.go
+++ b/libgo/go/websocket/websocket_test.go
@@ -15,6 +15,7 @@ import (
"net"
"sync"
"testing"
+ "url"
)
var serverAddr string
@@ -150,14 +151,14 @@ func TestHTTP(t *testing.T) {
// 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))
+ _, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
if err == nil {
t.Error("Get: unexpected success")
return
}
- urlerr, ok := err.(*http.URLError)
+ urlerr, ok := err.(*url.Error)
if !ok {
- t.Errorf("Get: not URLError %#v", err)
+ t.Errorf("Get: not url.Error %#v", err)
return
}
if urlerr.Error != io.ErrUnexpectedEOF {
@@ -169,7 +170,7 @@ func TestHTTP(t *testing.T) {
func TestHTTPDraft75(t *testing.T) {
once.Do(startServer)
- r, _, err := http.Get(fmt.Sprintf("http://%s/echoDraft75", serverAddr))
+ r, err := http.Get(fmt.Sprintf("http://%s/echoDraft75", serverAddr))
if err != nil {
t.Errorf("Get: error %#v", err)
return
diff --git a/libgo/go/xml/atom_test.go b/libgo/go/xml/atom_test.go
new file mode 100644
index 00000000000..d365510bf58
--- /dev/null
+++ b/libgo/go/xml/atom_test.go
@@ -0,0 +1,50 @@
+// 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 xml
+
+var atomValue = &Feed{
+ Title: "Example Feed",
+ Link: []Link{{Href: "http://example.org/"}},
+ Updated: ParseTime("2003-12-13T18:30:02Z"),
+ Author: Person{Name: "John Doe"},
+ Id: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6",
+
+ Entry: []Entry{
+ {
+ Title: "Atom-Powered Robots Run Amok",
+ Link: []Link{{Href: "http://example.org/2003/12/13/atom03"}},
+ Id: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
+ Updated: ParseTime("2003-12-13T18:30:02Z"),
+ Summary: NewText("Some text."),
+ },
+ },
+}
+
+var atomXml = `` +
+ `<feed xmlns="http://www.w3.org/2005/Atom">` +
+ `<Title>Example Feed</Title>` +
+ `<Id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</Id>` +
+ `<Link href="http://example.org/"></Link>` +
+ `<Updated>2003-12-13T18:30:02Z</Updated>` +
+ `<Author><Name>John Doe</Name><URI></URI><Email></Email></Author>` +
+ `<Entry>` +
+ `<Title>Atom-Powered Robots Run Amok</Title>` +
+ `<Id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</Id>` +
+ `<Link href="http://example.org/2003/12/13/atom03"></Link>` +
+ `<Updated>2003-12-13T18:30:02Z</Updated>` +
+ `<Author><Name></Name><URI></URI><Email></Email></Author>` +
+ `<Summary>Some text.</Summary>` +
+ `</Entry>` +
+ `</feed>`
+
+func ParseTime(str string) Time {
+ return Time(str)
+}
+
+func NewText(text string) Text {
+ return Text{
+ Body: text,
+ }
+}
diff --git a/libgo/go/xml/embed_test.go b/libgo/go/xml/embed_test.go
index abfe781acdf..ec7f478bec3 100644
--- a/libgo/go/xml/embed_test.go
+++ b/libgo/go/xml/embed_test.go
@@ -12,14 +12,14 @@ type C struct {
}
type A struct {
- XMLName Name "http://domain a"
+ XMLName Name `xml:"http://domain a"`
C
B B
FieldA string
}
type B struct {
- XMLName Name "b"
+ XMLName Name `xml:"b"`
C
FieldB string
}
@@ -65,7 +65,7 @@ func TestEmbedded1(t *testing.T) {
}
type A2 struct {
- XMLName Name "http://domain a"
+ XMLName Name `xml:"http://domain a"`
XY string
Xy string
}
@@ -92,7 +92,7 @@ func TestEmbedded2(t *testing.T) {
}
type A3 struct {
- XMLName Name "http://domain a"
+ XMLName Name `xml:"http://domain a"`
xy string
}
@@ -108,7 +108,7 @@ func TestEmbedded3(t *testing.T) {
}
type A4 struct {
- XMLName Name "http://domain a"
+ XMLName Name `xml:"http://domain a"`
Any string
}
diff --git a/libgo/go/xml/marshal.go b/libgo/go/xml/marshal.go
new file mode 100644
index 00000000000..ea421c1b17d
--- /dev/null
+++ b/libgo/go/xml/marshal.go
@@ -0,0 +1,228 @@
+// 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 xml
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+const (
+ // A generic XML header suitable for use with the output of Marshal and
+ // MarshalIndent. This is not automatically added to any output of this
+ // package, it is provided as a convenience.
+ Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
+)
+
+// A Marshaler can produce well-formatted XML representing its internal state.
+// It is used by both Marshal and MarshalIndent.
+type Marshaler interface {
+ MarshalXML() ([]byte, os.Error)
+}
+
+type printer struct {
+ *bufio.Writer
+}
+
+// Marshal writes an XML-formatted representation of v to w.
+//
+// If v implements Marshaler, then Marshal calls its MarshalXML method.
+// Otherwise, Marshal uses the following procedure to create the XML.
+//
+// Marshal handles an array or slice by marshalling each of the elements.
+// Marshal handles a pointer by marshalling the value it points at or, if the
+// pointer is nil, by writing nothing. Marshal handles an interface value by
+// marshalling the value it contains or, if the interface value is nil, by
+// writing nothing. Marshal handles all other data by writing a single XML
+// element containing the data.
+//
+// The name of that XML element is taken from, in order of preference:
+// - the tag on an XMLName field, if the data is a struct
+// - the value of an XMLName field of type xml.Name
+// - the tag of the struct field used to obtain the data
+// - the name of the struct field used to obtain the data
+// - the name '???'.
+//
+// The XML element for a struct contains marshalled elements for each of the
+// exported fields of the struct, with these exceptions:
+// - the XMLName field, described above, is omitted.
+// - a field with tag "attr" becomes an attribute in the XML element.
+// - a field with tag "chardata" is written as character data,
+// not as an XML element.
+// - a field with tag "innerxml" is written verbatim,
+// not subject to the usual marshalling procedure.
+//
+// Marshal will return an error if asked to marshal a channel, function, or map.
+func Marshal(w io.Writer, v interface{}) (err os.Error) {
+ p := &printer{bufio.NewWriter(w)}
+ err = p.marshalValue(reflect.ValueOf(v), "???")
+ p.Flush()
+ return err
+}
+
+func (p *printer) marshalValue(val reflect.Value, name string) os.Error {
+ if !val.IsValid() {
+ return nil
+ }
+
+ kind := val.Kind()
+ typ := val.Type()
+
+ // Try Marshaler
+ if typ.NumMethod() > 0 {
+ if marshaler, ok := val.Interface().(Marshaler); ok {
+ bytes, err := marshaler.MarshalXML()
+ if err != nil {
+ return err
+ }
+ p.Write(bytes)
+ return nil
+ }
+ }
+
+ // Drill into pointers/interfaces
+ if kind == reflect.Ptr || kind == reflect.Interface {
+ if val.IsNil() {
+ return nil
+ }
+ return p.marshalValue(val.Elem(), name)
+ }
+
+ // Slices and arrays iterate over the elements. They do not have an enclosing tag.
+ if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 {
+ for i, n := 0, val.Len(); i < n; i++ {
+ if err := p.marshalValue(val.Index(i), name); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ // Find XML name
+ xmlns := ""
+ if kind == reflect.Struct {
+ if f, ok := typ.FieldByName("XMLName"); ok {
+ if tag := f.Tag.Get("xml"); tag != "" {
+ if i := strings.Index(tag, " "); i >= 0 {
+ xmlns, name = tag[:i], tag[i+1:]
+ } else {
+ name = tag
+ }
+ } else if v, ok := val.FieldByIndex(f.Index).Interface().(Name); ok && v.Local != "" {
+ xmlns, name = v.Space, v.Local
+ }
+ }
+ }
+
+ p.WriteByte('<')
+ p.WriteString(name)
+
+ // Attributes
+ if kind == reflect.Struct {
+ if len(xmlns) > 0 {
+ p.WriteString(` xmlns="`)
+ Escape(p, []byte(xmlns))
+ p.WriteByte('"')
+ }
+
+ for i, n := 0, typ.NumField(); i < n; i++ {
+ if f := typ.Field(i); f.PkgPath == "" && f.Tag.Get("xml") == "attr" {
+ if f.Type.Kind() == reflect.String {
+ if str := val.Field(i).String(); str != "" {
+ p.WriteByte(' ')
+ p.WriteString(strings.ToLower(f.Name))
+ p.WriteString(`="`)
+ Escape(p, []byte(str))
+ p.WriteByte('"')
+ }
+ }
+ }
+ }
+ }
+ p.WriteByte('>')
+
+ switch k := val.Kind(); k {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p.WriteString(strconv.Itoa64(val.Int()))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p.WriteString(strconv.Uitoa64(val.Uint()))
+ case reflect.Float32, reflect.Float64:
+ p.WriteString(strconv.Ftoa64(val.Float(), 'g', -1))
+ case reflect.String:
+ Escape(p, []byte(val.String()))
+ case reflect.Bool:
+ p.WriteString(strconv.Btoa(val.Bool()))
+ case reflect.Array:
+ // will be [...]byte
+ bytes := make([]byte, val.Len())
+ for i := range bytes {
+ bytes[i] = val.Index(i).Interface().(byte)
+ }
+ Escape(p, bytes)
+ case reflect.Slice:
+ // will be []byte
+ bytes := val.Interface().([]byte)
+ Escape(p, bytes)
+ case reflect.Struct:
+ for i, n := 0, val.NumField(); i < n; i++ {
+ if f := typ.Field(i); f.Name != "XMLName" && f.PkgPath == "" {
+ name := f.Name
+ switch tag := f.Tag.Get("xml"); tag {
+ case "":
+ case "chardata":
+ if tk := f.Type.Kind(); tk == reflect.String {
+ Escape(p, []byte(val.Field(i).String()))
+ } else if tk == reflect.Slice {
+ if elem, ok := val.Field(i).Interface().([]byte); ok {
+ Escape(p, elem)
+ }
+ }
+ continue
+ case "innerxml":
+ iface := val.Field(i).Interface()
+ switch raw := iface.(type) {
+ case []byte:
+ p.Write(raw)
+ continue
+ case string:
+ p.WriteString(raw)
+ continue
+ }
+ case "attr":
+ continue
+ default:
+ name = tag
+ }
+
+ if err := p.marshalValue(val.Field(i), name); err != nil {
+ return err
+ }
+ }
+ }
+ default:
+ return &UnsupportedTypeError{typ}
+ }
+
+ p.WriteByte('<')
+ p.WriteByte('/')
+ p.WriteString(name)
+ p.WriteByte('>')
+
+ return nil
+}
+
+// A MarshalXMLError is returned when Marshal or MarshalIndent encounter a type
+// that cannot be converted into XML.
+type UnsupportedTypeError struct {
+ Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) String() string {
+ return "xml: unsupported type: " + e.Type.String()
+}
diff --git a/libgo/go/xml/marshal_test.go b/libgo/go/xml/marshal_test.go
new file mode 100644
index 00000000000..5b972fafe67
--- /dev/null
+++ b/libgo/go/xml/marshal_test.go
@@ -0,0 +1,305 @@
+// 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 xml
+
+import (
+ "reflect"
+ "testing"
+
+ "os"
+ "bytes"
+ "strings"
+ "strconv"
+)
+
+type DriveType int
+
+const (
+ HyperDrive DriveType = iota
+ ImprobabilityDrive
+)
+
+type Passenger struct {
+ Name []string `xml:"name"`
+ Weight float32 `xml:"weight"`
+}
+
+type Ship struct {
+ XMLName Name `xml:"spaceship"`
+
+ Name string `xml:"attr"`
+ Pilot string `xml:"attr"`
+ Drive DriveType `xml:"drive"`
+ Age uint `xml:"age"`
+ Passenger []*Passenger `xml:"passenger"`
+ secret string
+}
+
+type RawXML string
+
+func (rx RawXML) MarshalXML() ([]byte, os.Error) {
+ return []byte(rx), nil
+}
+
+type NamedType string
+
+type Port struct {
+ XMLName Name `xml:"port"`
+ Type string `xml:"attr"`
+ Number string `xml:"chardata"`
+}
+
+type Domain struct {
+ XMLName Name `xml:"domain"`
+ Country string `xml:"attr"`
+ Name []byte `xml:"chardata"`
+}
+
+type Book struct {
+ XMLName Name `xml:"book"`
+ Title string `xml:"chardata"`
+}
+
+type SecretAgent struct {
+ XMLName Name `xml:"agent"`
+ Handle string `xml:"attr"`
+ Identity string
+ Obfuscate string `xml:"innerxml"`
+}
+
+var nilStruct *Ship
+
+var marshalTests = []struct {
+ Value interface{}
+ ExpectXML string
+}{
+ // Test nil marshals to nothing
+ {Value: nil, ExpectXML: ``},
+ {Value: nilStruct, ExpectXML: ``},
+
+ // Test value types (no tag name, so ???)
+ {Value: true, ExpectXML: `<???>true</???>`},
+ {Value: int(42), ExpectXML: `<???>42</???>`},
+ {Value: int8(42), ExpectXML: `<???>42</???>`},
+ {Value: int16(42), ExpectXML: `<???>42</???>`},
+ {Value: int32(42), ExpectXML: `<???>42</???>`},
+ {Value: uint(42), ExpectXML: `<???>42</???>`},
+ {Value: uint8(42), ExpectXML: `<???>42</???>`},
+ {Value: uint16(42), ExpectXML: `<???>42</???>`},
+ {Value: uint32(42), ExpectXML: `<???>42</???>`},
+ {Value: float32(1.25), ExpectXML: `<???>1.25</???>`},
+ {Value: float64(1.25), ExpectXML: `<???>1.25</???>`},
+ {Value: uintptr(0xFFDD), ExpectXML: `<???>65501</???>`},
+ {Value: "gopher", ExpectXML: `<???>gopher</???>`},
+ {Value: []byte("gopher"), ExpectXML: `<???>gopher</???>`},
+ {Value: "</>", ExpectXML: `<???>&lt;/&gt;</???>`},
+ {Value: []byte("</>"), ExpectXML: `<???>&lt;/&gt;</???>`},
+ {Value: [3]byte{'<', '/', '>'}, ExpectXML: `<???>&lt;/&gt;</???>`},
+ {Value: NamedType("potato"), ExpectXML: `<???>potato</???>`},
+ {Value: []int{1, 2, 3}, ExpectXML: `<???>1</???><???>2</???><???>3</???>`},
+ {Value: [3]int{1, 2, 3}, ExpectXML: `<???>1</???><???>2</???><???>3</???>`},
+
+ // Test innerxml
+ {Value: RawXML("</>"), ExpectXML: `</>`},
+ {
+ Value: &SecretAgent{
+ Handle: "007",
+ Identity: "James Bond",
+ Obfuscate: "<redacted/>",
+ },
+ //ExpectXML: `<agent handle="007"><redacted/></agent>`,
+ ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
+ },
+
+ // Test structs
+ {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
+ {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
+ {Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
+ {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
+ {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
+ {Value: atomValue, ExpectXML: atomXml},
+ {
+ Value: &Ship{
+ Name: "Heart of Gold",
+ Pilot: "Computer",
+ Age: 1,
+ Drive: ImprobabilityDrive,
+ Passenger: []*Passenger{
+ &Passenger{
+ Name: []string{"Zaphod", "Beeblebrox"},
+ Weight: 7.25,
+ },
+ &Passenger{
+ Name: []string{"Trisha", "McMillen"},
+ Weight: 5.5,
+ },
+ &Passenger{
+ Name: []string{"Ford", "Prefect"},
+ Weight: 7,
+ },
+ &Passenger{
+ Name: []string{"Arthur", "Dent"},
+ Weight: 6.75,
+ },
+ },
+ },
+ ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
+ `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
+ `<age>1</age>` +
+ `<passenger>` +
+ `<name>Zaphod</name>` +
+ `<name>Beeblebrox</name>` +
+ `<weight>7.25</weight>` +
+ `</passenger>` +
+ `<passenger>` +
+ `<name>Trisha</name>` +
+ `<name>McMillen</name>` +
+ `<weight>5.5</weight>` +
+ `</passenger>` +
+ `<passenger>` +
+ `<name>Ford</name>` +
+ `<name>Prefect</name>` +
+ `<weight>7</weight>` +
+ `</passenger>` +
+ `<passenger>` +
+ `<name>Arthur</name>` +
+ `<name>Dent</name>` +
+ `<weight>6.75</weight>` +
+ `</passenger>` +
+ `</spaceship>`,
+ },
+}
+
+func TestMarshal(t *testing.T) {
+ for idx, test := range marshalTests {
+ buf := bytes.NewBuffer(nil)
+ err := Marshal(buf, test.Value)
+ if err != nil {
+ t.Errorf("#%d: Error: %s", idx, err)
+ continue
+ }
+ if got, want := buf.String(), test.ExpectXML; got != want {
+ if strings.Contains(want, "\n") {
+ t.Errorf("#%d: marshal(%#v) - GOT:\n%s\nWANT:\n%s", idx, test.Value, got, want)
+ } else {
+ t.Errorf("#%d: marshal(%#v) = %#q want %#q", idx, test.Value, got, want)
+ }
+ }
+ }
+}
+
+var marshalErrorTests = []struct {
+ Value interface{}
+ ExpectErr string
+ ExpectKind reflect.Kind
+}{
+ {
+ Value: make(chan bool),
+ ExpectErr: "xml: unsupported type: chan bool",
+ ExpectKind: reflect.Chan,
+ },
+ {
+ Value: map[string]string{
+ "question": "What do you get when you multiply six by nine?",
+ "answer": "42",
+ },
+ ExpectErr: "xml: unsupported type: map[string] string",
+ ExpectKind: reflect.Map,
+ },
+ {
+ Value: map[*Ship]bool{nil: false},
+ ExpectErr: "xml: unsupported type: map[*xml.Ship] bool",
+ ExpectKind: reflect.Map,
+ },
+}
+
+func TestMarshalErrors(t *testing.T) {
+ for idx, test := range marshalErrorTests {
+ buf := bytes.NewBuffer(nil)
+ err := Marshal(buf, test.Value)
+ if got, want := err, test.ExpectErr; got == nil {
+ t.Errorf("#%d: want error %s", idx, want)
+ continue
+ } else if got.String() != want {
+ t.Errorf("#%d: marshal(%#v) = [error] %q, want %q", idx, test.Value, got, want)
+ }
+ if got, want := err.(*UnsupportedTypeError).Type.Kind(), test.ExpectKind; got != want {
+ t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, got, want)
+ }
+ }
+}
+
+// Do invertibility testing on the various structures that we test
+func TestUnmarshal(t *testing.T) {
+ for i, test := range marshalTests {
+ // Skip the nil pointers
+ if i <= 1 {
+ continue
+ }
+
+ var dest interface{}
+
+ switch test.Value.(type) {
+ case *Ship, Ship:
+ dest = &Ship{}
+ case *Port, Port:
+ dest = &Port{}
+ case *Domain, Domain:
+ dest = &Domain{}
+ case *Feed, Feed:
+ dest = &Feed{}
+ default:
+ continue
+ }
+
+ buffer := bytes.NewBufferString(test.ExpectXML)
+ err := Unmarshal(buffer, dest)
+
+ // Don't compare XMLNames
+ switch fix := dest.(type) {
+ case *Ship:
+ fix.XMLName = Name{}
+ case *Port:
+ fix.XMLName = Name{}
+ case *Domain:
+ fix.XMLName = Name{}
+ case *Feed:
+ fix.XMLName = Name{}
+ fix.Author.InnerXML = ""
+ for i := range fix.Entry {
+ fix.Entry[i].Author.InnerXML = ""
+ }
+ }
+
+ if err != nil {
+ t.Errorf("#%d: unexpected error: %#v", i, err)
+ } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
+ t.Errorf("#%d: unmarshal(%#s) = %#v, want %#v", i, test.ExpectXML, got, want)
+ }
+ }
+}
+
+func BenchmarkMarshal(b *testing.B) {
+ idx := len(marshalTests) - 1
+ test := marshalTests[idx]
+
+ buf := bytes.NewBuffer(nil)
+ for i := 0; i < b.N; i++ {
+ Marshal(buf, test.Value)
+ buf.Truncate(0)
+ }
+}
+
+func BenchmarkUnmarshal(b *testing.B) {
+ idx := len(marshalTests) - 1
+ test := marshalTests[idx]
+ sm := &Ship{}
+ xml := []byte(test.ExpectXML)
+
+ for i := 0; i < b.N; i++ {
+ buffer := bytes.NewBuffer(xml)
+ Unmarshal(buffer, sm)
+ }
+}
diff --git a/libgo/go/xml/read.go b/libgo/go/xml/read.go
index e2b349c3ffb..786b69f5a32 100644
--- a/libgo/go/xml/read.go
+++ b/libgo/go/xml/read.go
@@ -31,16 +31,16 @@ import (
// For example, given these definitions:
//
// type Email struct {
-// Where string "attr"
+// Where string `xml:"attr"`
// Addr string
// }
//
// type Result struct {
-// XMLName xml.Name "result"
+// XMLName xml.Name `xml:"result"`
// Name string
// Phone string
// Email []Email
-// Groups []string "group>value"
+// Groups []string `xml:"group>value"`
// }
//
// result := Result{Name: "name", Phone: "phone", Email: nil}
@@ -79,11 +79,13 @@ import (
// 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
+// Because Unmarshal uses the reflect package, it can only assign
+// to exported (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:
+// Unmarshal maps an XML element to a struct using the following rules.
+// In the rules, the tag of a field refers to the value associated with the
+// key 'xml' in the struct field's tag (see the example above).
//
// * If the struct has a field of type []byte or string with tag "innerxml",
// Unmarshal accumulates the raw XML nested inside the element
@@ -92,9 +94,9 @@ import (
// * 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
+// * If the XMLName field has an associated tag of the form
+// "name" or "namespace-URL name", the XML element must have
+// the given name (and, optionally, name space) or else Unmarshal
// returns an error.
//
// * If the XML element has an attribute whose name matches a
@@ -106,31 +108,41 @@ import (
// The struct field may have type []byte or string.
// If there is no such field, the character data is discarded.
//
+// * If the XML element contains comments, they are accumulated in
+// the first struct field that has tag "comments". The struct
+// field may have type []byte or string. If there is no such
+// field, the comments are discarded.
+//
// * If the XML element contains a sub-element whose name matches
-// the prefix of a struct field tag formatted as "a>b>c", unmarshal
+// the prefix of a 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
+// A 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",
+// matches a 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.
+// concatenation of that element's character data in the string or
+// []byte.
+//
+// Unmarshal maps an attribute value to a string or []byte by saving
+// the value in the string or slice.
//
-// Unmarshal maps an XML element to a slice by extending the length
-// of the slice and mapping the element to the newly created value.
+// Unmarshal maps an XML element to a slice by extending the length of
+// the slice and mapping the element to the newly created value.
//
-// Unmarshal maps an XML element to a bool by setting it to the boolean
-// value represented by the string.
+// Unmarshal maps an XML element or attribute value to a bool by
+// setting it to the boolean value represented by the string.
//
-// Unmarshal maps an XML element to an integer or floating-point
-// field by setting the field to the result of interpreting the string
-// value in decimal. There is no check for overflow.
+// Unmarshal maps an XML element or attribute value to an integer or
+// floating-point field by setting the field to the result of
+// interpreting the string value in decimal. There is no check for
+// overflow.
//
// Unmarshal maps an XML element to an xml.Name by recording the
// element name.
@@ -241,7 +253,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
switch v := val; v.Kind() {
default:
- return os.ErrorString("unknown type " + v.Type().String())
+ return os.NewError("unknown type " + v.Type().String())
case reflect.Slice:
typ := v.Type()
@@ -287,8 +299,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
// Assign name.
if f, ok := typ.FieldByName("XMLName"); ok {
// Validate element name.
- if f.Tag != "" {
- tag := f.Tag
+ if tag := f.Tag.Get("xml"); tag != "" {
ns := ""
i := strings.LastIndex(tag, " ")
if i >= 0 {
@@ -320,12 +331,9 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
// 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 {
+ switch f.Tag.Get("xml") {
case "attr":
strv := sv.FieldByIndex(f.Index)
- if strv.Kind() != reflect.String {
- return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
- }
// Look for attribute.
val := ""
k := strings.ToLower(f.Name)
@@ -335,7 +343,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
break
}
}
- strv.SetString(val)
+ copyValue(strv, []byte(val))
case "comment":
if !saveComment.IsValid() {
@@ -359,15 +367,15 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
}
default:
- if strings.Contains(f.Tag, ">") {
+ if tag := f.Tag.Get("xml"); strings.Contains(tag, ">") {
if fieldPaths == nil {
fieldPaths = make(map[string]pathInfo)
}
- path := strings.ToLower(f.Tag)
- if strings.HasPrefix(f.Tag, ">") {
+ path := strings.ToLower(tag)
+ if strings.HasPrefix(tag, ">") {
path = strings.ToLower(f.Name) + path
}
- if strings.HasSuffix(f.Tag, ">") {
+ if strings.HasSuffix(tag, ">") {
path = path[:len(path)-1]
}
err := addFieldPath(sv, fieldPaths, path, f.Index)
@@ -454,33 +462,54 @@ Loop:
}
}
- var err os.Error
+ if err := copyValue(saveData, data); err != nil {
+ return err
+ }
+
+ switch t := saveComment; t.Kind() {
+ case reflect.String:
+ t.SetString(string(comment))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(comment))
+ }
+
+ switch t := saveXML; t.Kind() {
+ case reflect.String:
+ t.SetString(string(saveXMLData))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(saveXMLData))
+ }
+
+ return nil
+}
+
+func copyValue(dst reflect.Value, src []byte) (err os.Error) {
// Helper functions for integer and unsigned integer conversions
var itmp int64
getInt64 := func() bool {
- itmp, err = strconv.Atoi64(string(data))
+ itmp, err = strconv.Atoi64(string(src))
// TODO: should check sizes
return err == nil
}
var utmp uint64
getUint64 := func() bool {
- utmp, err = strconv.Atoui64(string(data))
+ utmp, err = strconv.Atoui64(string(src))
// TODO: check for overflow?
return err == nil
}
var ftmp float64
getFloat64 := func() bool {
- ftmp, err = strconv.Atof64(string(data))
+ ftmp, err = strconv.Atof64(string(src))
// TODO: check for overflow?
return err == nil
}
// Save accumulated data and comments
- switch t := saveData; t.Kind() {
+ switch t := dst; t.Kind() {
case reflect.Invalid:
// Probably a comment, handled below
default:
- return os.ErrorString("cannot happen: unknown type " + t.Type().String())
+ return os.NewError("cannot happen: unknown type " + t.Type().String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if !getInt64() {
return err
@@ -497,31 +526,16 @@ Loop:
}
t.SetFloat(ftmp)
case reflect.Bool:
- value, err := strconv.Atob(strings.TrimSpace(string(data)))
+ value, err := strconv.Atob(strings.TrimSpace(string(src)))
if err != nil {
return err
}
t.SetBool(value)
case reflect.String:
- t.SetString(string(data))
+ t.SetString(string(src))
case reflect.Slice:
- t.Set(reflect.ValueOf(data))
+ t.Set(reflect.ValueOf(src))
}
-
- switch t := saveComment; t.Kind() {
- case reflect.String:
- t.SetString(string(comment))
- case reflect.Slice:
- t.Set(reflect.ValueOf(comment))
- }
-
- switch t := saveXML; t.Kind() {
- case reflect.String:
- t.SetString(string(saveXMLData))
- case reflect.Slice:
- t.Set(reflect.ValueOf(saveXMLData))
- }
-
return nil
}
@@ -561,7 +575,7 @@ func tagError(sv reflect.Value, idx1 []int, idx2 []int) os.Error {
t := sv.Type()
f1 := t.FieldByIndex(idx1)
f2 := t.FieldByIndex(idx2)
- return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
+ return &TagPathError{t, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")}
}
// unmarshalPaths walks down an XML structure looking for
diff --git a/libgo/go/xml/read_test.go b/libgo/go/xml/read_test.go
index d4ae3700dba..2126da3c751 100644
--- a/libgo/go/xml/read_test.go
+++ b/libgo/go/xml/read_test.go
@@ -78,7 +78,7 @@ not being used from outside intra_region_diff.py.
</summary></entry></feed> `
type Feed struct {
- XMLName Name "http://www.w3.org/2005/Atom feed"
+ XMLName Name `xml:"http://www.w3.org/2005/Atom feed"`
Title string
Id string
Link []Link
@@ -97,20 +97,20 @@ type Entry struct {
}
type Link struct {
- Rel string "attr"
- Href string "attr"
+ Rel string `xml:"attr"`
+ Href string `xml:"attr"`
}
type Person struct {
Name string
URI string
Email string
- InnerXML string "innerxml"
+ InnerXML string `xml:"innerxml"`
}
type Text struct {
- Type string "attr"
- Body string "chardata"
+ Type string `xml:"attr"`
+ Body string `xml:"chardata"`
}
type Time string
@@ -255,18 +255,18 @@ type PathTestItem struct {
}
type PathTestA struct {
- Items []PathTestItem ">item1"
+ Items []PathTestItem `xml:">item1"`
Before, After string
}
type PathTestB struct {
- Other []PathTestItem "items>Item1"
+ Other []PathTestItem `xml:"items>Item1"`
Before, After string
}
type PathTestC struct {
- Values1 []string "items>item1>value"
- Values2 []string "items>item2>value"
+ Values1 []string `xml:"items>item1>value"`
+ Values2 []string `xml:"items>item2>value"`
Before, After string
}
@@ -275,7 +275,7 @@ type PathTestSet struct {
}
type PathTestD struct {
- Other PathTestSet "items>"
+ Other PathTestSet `xml:"items>"`
Before, After string
}
@@ -299,15 +299,15 @@ func TestUnmarshalPaths(t *testing.T) {
}
type BadPathTestA struct {
- First string "items>item1"
- Other string "items>item2"
- Second string "items>"
+ First string `xml:"items>item1"`
+ Other string `xml:"items>item2"`
+ Second string `xml:"items>"`
}
type BadPathTestB struct {
- Other string "items>item2>value"
- First string "items>item1"
- Second string "items>item1>value"
+ Other string `xml:"items>item2>value"`
+ First string `xml:"items>item1"`
+ Second string `xml:"items>item1>value"`
}
var badPathTests = []struct {
@@ -325,3 +325,47 @@ func TestUnmarshalBadPaths(t *testing.T) {
}
}
}
+
+func TestUnmarshalAttrs(t *testing.T) {
+ var f AttrTest
+ if err := Unmarshal(StringReader(attrString), &f); err != nil {
+ t.Fatalf("Unmarshal: %s", err)
+ }
+ if !reflect.DeepEqual(f, attrStruct) {
+ t.Fatalf("have %#v\nwant %#v", f, attrStruct)
+ }
+}
+
+type AttrTest struct {
+ Test1 Test1
+ Test2 Test2
+}
+
+type Test1 struct {
+ Int int `xml:"attr"`
+ Float float64 `xml:"attr"`
+ Uint8 uint8 `xml:"attr"`
+}
+
+type Test2 struct {
+ Bool bool `xml:"attr"`
+}
+
+const attrString = `
+<?xml version="1.0" charset="utf-8"?>
+<attrtest>
+ <test1 int="8" float="23.5" uint8="255"/>
+ <test2 bool="true"/>
+</attrtest>
+`
+
+var attrStruct = AttrTest{
+ Test1: Test1{
+ Int: 8,
+ Float: 23.5,
+ Uint8: 255,
+ },
+ Test2: Test2{
+ Bool: true,
+ },
+}
diff --git a/libgo/go/xml/xml.go b/libgo/go/xml/xml.go
index 42d8b986ecc..e7ba44e4a26 100644
--- a/libgo/go/xml/xml.go
+++ b/libgo/go/xml/xml.go
@@ -416,7 +416,6 @@ func (p *Parser) autoClose(t Token) (Token, bool) {
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.
@@ -659,17 +658,22 @@ func (p *Parser) RawToken() (Token, os.Error) {
return nil, p.err
}
if b != '=' {
- p.err = p.syntaxError("attribute name without = in element")
- return nil, p.err
- }
- p.space()
- data := p.attrval()
- if data == nil {
- return nil, p.err
+ if p.Strict {
+ p.err = p.syntaxError("attribute name without = in element")
+ return nil, p.err
+ } else {
+ p.ungetc(b)
+ a.Value = a.Name.Local
+ }
+ } else {
+ p.space()
+ data := p.attrval()
+ if data == nil {
+ return nil, p.err
+ }
+ a.Value = string(data)
}
- a.Value = string(data)
}
-
if empty {
p.needClose = true
p.toClose = name
@@ -1028,312 +1032,316 @@ func isNameByte(c byte) bool {
// 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 first = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {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},
+var second = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {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
diff --git a/libgo/go/xml/xml_test.go b/libgo/go/xml/xml_test.go
index 4e51cd53af1..64076240557 100644
--- a/libgo/go/xml/xml_test.go
+++ b/libgo/go/xml/xml_test.go
@@ -445,6 +445,33 @@ func TestUnquotedAttrs(t *testing.T) {
}
}
+func TestValuelessAttrs(t *testing.T) {
+ tests := [][3]string{
+ {"<p nowrap>", "p", "nowrap"},
+ {"<p nowrap >", "p", "nowrap"},
+ {"<input checked/>", "input", "checked"},
+ {"<input checked />", "input", "checked"},
+ }
+ for _, test := range tests {
+ p := NewParser(StringReader(test[0]))
+ p.Strict = false
+ token, err := p.Token()
+ if _, ok := err.(*SyntaxError); ok {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if token.(StartElement).Name.Local != test[1] {
+ t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
+ }
+ attr := token.(StartElement).Attr[0]
+ if attr.Value != test[2] {
+ t.Errorf("Unexpected attribute value: %v", attr.Value)
+ }
+ if attr.Name.Local != test[2] {
+ t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
+ }
+ }
+}
+
func TestCopyTokenCharData(t *testing.T) {
data := []byte("same data")
var tok1 Token = CharData(data)
@@ -519,7 +546,6 @@ func TestEntityInsideCDATA(t *testing.T) {
}
}
-
// 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
@@ -540,7 +566,6 @@ var characterTests = []struct {
{"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &;"},
}
-
func TestDisallowedCharacters(t *testing.T) {
for i, tt := range characterTests {
diff --git a/libgo/merge.sh b/libgo/merge.sh
index 3696783abbe..3c520ef3bf9 100644
--- a/libgo/merge.sh
+++ b/libgo/merge.sh
@@ -32,13 +32,13 @@ fi
repository=$1
-merge_rev=`sed 1q MERGE`
+old_rev=`sed 1q MERGE`
rm -rf ${OLDDIR}
-hg clone -r ${merge_rev} ${repository} ${OLDDIR}
+hg clone -r ${old_rev} ${repository} ${OLDDIR}
rm -rf ${NEWDIR}
-hg clone ${repository} ${NEWDIR}
+hg clone -u release ${repository} ${NEWDIR}
new_rev=`cd ${NEWDIR} && hg log | sed 1q | sed -e 's/.*://'`
diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh
index a837cbaed71..edeb3168a8a 100755
--- a/libgo/mksysinfo.sh
+++ b/libgo/mksysinfo.sh
@@ -42,6 +42,7 @@ cat > sysinfo.c <<EOF
#endif
#include <netinet/tcp.h>
#include <signal.h>
+#include <sys/ioctl.h>
#if defined(HAVE_SYSCALL_H)
#include <syscall.h>
#endif
@@ -76,11 +77,24 @@ cat > sysinfo.c <<EOF
#include <unistd.h>
#include <netdb.h>
#include <pwd.h>
+#if defined(HAVE_LINUX_FILTER_H)
+#include <linux/filter.h>
+#endif
+#if defined(HAVE_LINUX_NETLINK_H)
+#include <linux/netlink.h>
+#endif
+#if defined(HAVE_LINUX_RTNETLINK_H)
+#include <linux/rtnetlink.h>
+#endif
+#if defined(HAVE_NET_IF_H)
+#include <net/if.h>
+#endif
EOF
${CC} -fdump-go-spec=gen-sysinfo.go -std=gnu99 -S -o sysinfo.s sysinfo.c
echo 'package syscall' > ${OUT}
+echo 'import "unsafe"' >> ${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
@@ -449,7 +463,7 @@ echo $msghdr | \
# The ip_mreq struct
grep '^type _ip_mreq ' gen-sysinfo.go | \
- sed -e 's/_ip_mreq/IpMreq/' \
+ sed -e 's/_ip_mreq/IPMreq/' \
-e 's/imr_multiaddr/Multiaddr/' \
-e 's/imr_interface/Interface/' \
-e 's/_in_addr/[4]byte/g' \
@@ -479,4 +493,96 @@ grep '^type _passwd ' gen-sysinfo.go | \
-e 's/ pw_/ Pw_/g' \
>> ${OUT}
+# The ioctl flags for the controlling TTY.
+grep '^const _TIOC' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(TIOC[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# The nlmsghdr struct.
+grep '^type _nlmsghdr ' gen-sysinfo.go | \
+ sed -e 's/_nlmsghdr/NlMsghdr/' \
+ -e 's/nlmsg_len/Len/' \
+ -e 's/nlmsg_type/Type/' \
+ -e 's/nlmsg_flags/Flags/' \
+ -e 's/nlmsg_seq/Seq/' \
+ -e 's/nlmsg_pid/Pid/' \
+ >> ${OUT}
+
+# The nlmsg flags and operators.
+grep '^const _NLM' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(NLM[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# NLMSG_HDRLEN is defined as an expression using sizeof.
+if ! grep '^const NLMSG_HDRLEN' ${OUT} > /dev/null 2>&1; then
+ if grep '^type NlMsghdr ' ${OUT} > /dev/null 2>&1; then
+ echo 'var NLMSG_HDRLEN = int((unsafe.Sizeof(NlMsghdr{}) + (NLMSG_ALIGNTO-1)) &^ (NLMSG_ALIGNTO-1))' >> ${OUT}
+ fi
+fi
+
+# The rtgenmsg struct.
+grep '^type _rtgenmsg ' gen-sysinfo.go | \
+ sed -e 's/_rtgenmsg/RtGenmsg/' \
+ -e 's/rtgen_family/Family/' \
+ >> ${OUT}
+
+# The routing message flags.
+grep '^const _RTA' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(RTA[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+grep '^const _RTM' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(RTM[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# The size of the rtgenmsg struct.
+if grep 'type RtGenmsg ' ${OUT} > /dev/null 2>&1; then
+ echo 'var SizeofRtGenmsg = int(unsafe.Sizeof(RtGenmsg{}))' >> ${OUT}
+fi
+
+# The ifinfomsg struct.
+grep '^type _ifinfomsg ' gen-sysinfo.go | \
+ sed -e 's/_ifinfomsg/IfInfomsg/' \
+ -e 's/ifi_family/Family/' \
+ -e 's/ifi_type/Type/' \
+ -e 's/ifi_index/Index/' \
+ -e 's/ifi_flags/Flags/' \
+ -e 's/ifi_change/Change/' \
+ >> ${OUT}
+
+# The interface information types and flags.
+grep '^const _IFA' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(IFA[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+grep '^const _IFLA' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(IFLA[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+grep '^const _IFF' gen-sysinfo.go | \
+ sed -e 's/^\(const \)_\(IFF[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+
+# The size of the ifinfomsg struct.
+if grep 'type IfInfomsg ' ${OUT} > /dev/null 2>&1; then
+ echo 'var SizeofIfInfomsg = int(unsafe.Sizeof(IfInfomsg{}))' >> ${OUT}
+fi
+
+# The ifaddrmsg struct.
+grep '^type _ifaddrmsg ' gen-sysinfo.go | \
+ sed -e 's/_ifaddrmsg/IfAddrmsg/' \
+ -e 's/ifa_family/Family/' \
+ -e 's/ifa_prefixlen/Prefixlen/' \
+ -e 's/ifa_flags/Flags/' \
+ -e 's/ifa_scope/Scope/' \
+ -e 's/ifa_index/Index/' \
+ >> ${OUT}
+
+# The size of the ifaddrmsg struct.
+if grep 'type IfAddrmsg ' ${OUT} > /dev/null 2>&1; then
+ echo 'var SizeofIfAddrmsg = int(unsafe.Sizeof(IfAddrmsg{}))' >> ${OUT}
+fi
+
+# The rtattr struct.
+grep '^type _rtattr ' gen-sysinfo.go | \
+ sed -e 's/_rtattr/RtAttr/' \
+ -e 's/rta_len/Len/' \
+ -e 's/rta_type/Type/' \
+ >> ${OUT}
+
+# The size of the rtattr struct.
+if grep 'type RtAttr ' ${OUT} > /dev/null 2>&1; then
+ echo 'var SizeofRtAttr = int(unsafe.Sizeof(RtAttr{}))' >> ${OUT}
+fi
+
exit $?
diff --git a/libgo/runtime/go-go.c b/libgo/runtime/go-go.c
index 3d8e9e62908..139162056b8 100644
--- a/libgo/runtime/go-go.c
+++ b/libgo/runtime/go-go.c
@@ -73,7 +73,7 @@ static sigset_t __go_thread_wait_sigset;
/* Remove the current thread from the list of threads. */
static void
-remove_current_thread (void)
+remove_current_thread (void *dummy __attribute__ ((unused)))
{
struct __go_thread_id *list_entry;
MCache *mcache;
@@ -92,7 +92,7 @@ remove_current_thread (void)
if (list_entry->next != NULL)
list_entry->next->prev = list_entry->prev;
- /* This will look runtime_mheap as needed. */
+ /* This will lock runtime_mheap as needed. */
runtime_MCache_ReleaseAll (mcache);
/* This should never deadlock--there shouldn't be any code that
@@ -139,6 +139,8 @@ start_go_thread (void *thread_arg)
m = newm;
+ pthread_cleanup_push (remove_current_thread, NULL);
+
list_entry = newm->list_entry;
pfn = list_entry->pfn;
@@ -166,7 +168,7 @@ start_go_thread (void *thread_arg)
(*pfn) (arg);
- remove_current_thread ();
+ pthread_cleanup_pop (1);
return NULL;
}
@@ -178,11 +180,14 @@ void Goexit (void) asm ("libgo_runtime.runtime.Goexit");
void
Goexit (void)
{
- remove_current_thread ();
pthread_exit (NULL);
abort ();
}
+/* Count of threads created. */
+
+static volatile int mcount;
+
/* Implement the go statement. */
void
@@ -224,6 +229,9 @@ __go_go (void (*pfn) (void*), void *arg)
newm->list_entry = list_entry;
+ newm->id = __sync_fetch_and_add (&mcount, 1);
+ newm->fastrand = 0x49f6428aUL + newm->id;
+
newm->mcache = runtime_allocmcache ();
/* Add the thread to the list of all threads, marked as tentative
@@ -536,12 +544,17 @@ __go_cachestats (void)
for (p = __go_all_thread_ids; p != NULL; p = p->next)
{
MCache *c;
+ int i;
+ runtime_purgecachedstats(p->m);
c = p->m->mcache;
- mstats.heap_alloc += c->local_alloc;
- c->local_alloc = 0;
- mstats.heap_objects += c->local_objects;
- c->local_objects = 0;
+ for (i = 0; i < NumSizeClasses; ++i)
+ {
+ mstats.by_size[i].nmalloc += c->local_by_size[i].nmalloc;
+ c->local_by_size[i].nmalloc = 0;
+ mstats.by_size[i].nfree += c->local_by_size[i].nfree;
+ c->local_by_size[i].nfree = 0;
+ }
}
}
diff --git a/libgo/runtime/go-gomaxprocs.c b/libgo/runtime/go-gomaxprocs.c
index 04dc448b854..65146c50120 100644
--- a/libgo/runtime/go-gomaxprocs.c
+++ b/libgo/runtime/go-gomaxprocs.c
@@ -7,9 +7,17 @@
/* 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");
+extern int GOMAXPROCS (int) asm ("libgo_runtime.runtime.GOMAXPROCS");
-void
-GOMAXPROCS (int n __attribute__ ((unused)))
+static int set = 1;
+
+int
+GOMAXPROCS (int n)
{
+ int ret;
+
+ ret = set;
+ if (n > 0)
+ set = n;
+ return ret;
}
diff --git a/libgo/runtime/go-rand.c b/libgo/runtime/go-rand.c
new file mode 100644
index 00000000000..9632efc09cd
--- /dev/null
+++ b/libgo/runtime/go-rand.c
@@ -0,0 +1,18 @@
+// Copyright 2009 The Go 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"
+
+uint32
+runtime_fastrand1(void)
+{
+ uint32 x;
+
+ x = m->fastrand;
+ x += x;
+ if(x & 0x80000000L)
+ x ^= 0x88888eefUL;
+ m->fastrand = x;
+ return x;
+}
diff --git a/libgo/runtime/go-reflect-chan.c b/libgo/runtime/go-reflect-chan.c
index 61e360212f0..e8b4366dc57 100644
--- a/libgo/runtime/go-reflect-chan.c
+++ b/libgo/runtime/go-reflect-chan.c
@@ -33,16 +33,21 @@ makechan (const struct __go_type_descriptor *typ, uint32_t size)
return (uintptr_t) ret;
}
-extern _Bool chansend (uintptr_t, uintptr_t, _Bool)
+extern _Bool chansend (struct __go_channel_type *, uintptr_t, uintptr_t, _Bool)
asm ("libgo_reflect.reflect.chansend");
_Bool
-chansend (uintptr_t ch, uintptr_t val_i, _Bool nb)
+chansend (struct __go_channel_type *ct, uintptr_t ch, uintptr_t val_i,
+ _Bool nb)
{
struct __go_channel *channel = (struct __go_channel *) ch;
uintptr_t element_size;
void *pv;
+ __go_assert (ct->__common.__code == GO_CHAN);
+ __go_assert (__go_type_descriptors_equal (ct->__element_type,
+ channel->element_type));
+
if (channel == NULL)
__go_panic_msg ("send to nil channel");
@@ -94,17 +99,22 @@ struct chanrecv_ret
_Bool received;
};
-extern struct chanrecv_ret chanrecv (uintptr_t, _Bool)
+extern struct chanrecv_ret chanrecv (struct __go_channel_type *, uintptr_t,
+ _Bool)
asm ("libgo_reflect.reflect.chanrecv");
struct chanrecv_ret
-chanrecv (uintptr_t ch, _Bool nb)
+chanrecv (struct __go_channel_type *ct, uintptr_t ch, _Bool nb)
{
struct __go_channel *channel = (struct __go_channel *) ch;
void *pv;
uintptr_t element_size;
struct chanrecv_ret ret;
+ __go_assert (ct->__common.__code == GO_CHAN);
+ __go_assert (__go_type_descriptors_equal (ct->__element_type,
+ channel->element_type));
+
element_size = channel->element_type->__size;
if (__go_is_pointer_type (channel->element_type))
diff --git a/libgo/runtime/go-reflect-map.c b/libgo/runtime/go-reflect-map.c
index 5559f6eadaf..eb0590602e0 100644
--- a/libgo/runtime/go-reflect-map.c
+++ b/libgo/runtime/go-reflect-map.c
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "go-alloc.h"
+#include "go-assert.h"
#include "go-panic.h"
#include "go-type.h"
#include "map.h"
@@ -21,11 +22,12 @@ struct mapaccess_ret
_Bool pres;
};
-extern struct mapaccess_ret mapaccess (uintptr_t, uintptr_t)
+extern struct mapaccess_ret mapaccess (struct __go_map_type *, uintptr_t,
+ uintptr_t)
asm ("libgo_reflect.reflect.mapaccess");
struct mapaccess_ret
-mapaccess (uintptr_t m, uintptr_t key_i)
+mapaccess (struct __go_map_type *mt, uintptr_t m, uintptr_t key_i)
{
struct __go_map *map = (struct __go_map *) m;
void *key;
@@ -36,18 +38,20 @@ mapaccess (uintptr_t m, uintptr_t key_i)
void *val;
void *pv;
- if (map == NULL)
- __go_panic_msg ("lookup in nil map");
+ __go_assert (mt->__common.__code == GO_MAP);
- key_descriptor = map->__descriptor->__map_descriptor->__key_type;
+ key_descriptor = mt->__key_type;
if (__go_is_pointer_type (key_descriptor))
key = &key_i;
else
key = (void *) key_i;
- p = __go_map_index (map, key, 0);
+ if (map == NULL)
+ p = NULL;
+ else
+ p = __go_map_index (map, key, 0);
- val_descriptor = map->__descriptor->__map_descriptor->__val_type;
+ val_descriptor = mt->__val_type;
if (__go_is_pointer_type (val_descriptor))
{
val = NULL;
@@ -71,20 +75,24 @@ mapaccess (uintptr_t m, uintptr_t key_i)
return ret;
}
-extern void mapassign (uintptr_t, uintptr_t, uintptr_t, _Bool)
+extern void mapassign (struct __go_map_type *, uintptr_t, uintptr_t,
+ uintptr_t, _Bool)
asm ("libgo_reflect.reflect.mapassign");
void
-mapassign (uintptr_t m, uintptr_t key_i, uintptr_t val_i, _Bool pres)
+mapassign (struct __go_map_type *mt, uintptr_t m, uintptr_t key_i,
+ uintptr_t val_i, _Bool pres)
{
struct __go_map *map = (struct __go_map *) m;
const struct __go_type_descriptor *key_descriptor;
void *key;
+ __go_assert (mt->__common.__code == GO_MAP);
+
if (map == NULL)
- __go_panic_msg ("lookup in nil map");
+ __go_panic_msg ("assignment to entry in nil map");
- key_descriptor = map->__descriptor->__map_descriptor->__key_type;
+ key_descriptor = mt->__key_type;
if (__go_is_pointer_type (key_descriptor))
key = &key_i;
else
@@ -100,7 +108,7 @@ mapassign (uintptr_t m, uintptr_t key_i, uintptr_t val_i, _Bool pres)
p = __go_map_index (map, key, 1);
- val_descriptor = map->__descriptor->__map_descriptor->__val_type;
+ val_descriptor = mt->__val_type;
if (__go_is_pointer_type (val_descriptor))
pv = &val_i;
else
@@ -122,14 +130,15 @@ maplen (uintptr_t m)
return (int32_t) map->__element_count;
}
-extern unsigned char *mapiterinit (uintptr_t)
+extern unsigned char *mapiterinit (struct __go_map_type *, uintptr_t)
asm ("libgo_reflect.reflect.mapiterinit");
unsigned char *
-mapiterinit (uintptr_t m)
+mapiterinit (struct __go_map_type *mt, uintptr_t m)
{
struct __go_hash_iter *it;
+ __go_assert (mt->__common.__code == GO_MAP);
it = __go_alloc (sizeof (struct __go_hash_iter));
__go_mapiterinit ((struct __go_map *) m, it);
return (unsigned char *) it;
diff --git a/libgo/runtime/go-select.c b/libgo/runtime/go-select.c
index 5ea521d423d..e425aae24c7 100644
--- a/libgo/runtime/go-select.c
+++ b/libgo/runtime/go-select.c
@@ -533,7 +533,9 @@ mark_all_channels_waiting (struct select_channel* channels, uintptr_t count,
uintptr_t j;
/* A channel may be selected for both read and write. */
- if (channels[channels[i].dup_index].is_send != is_send)
+ if (channels[channels[i].dup_index].is_send == is_send)
+ continue;
+ else
{
for (j = channels[i].dup_index + 1; j < i; ++j)
{
diff --git a/libgo/runtime/go-semacquire.c b/libgo/runtime/go-semacquire.c
index 24c6a7388f6..40fe2af7864 100644
--- a/libgo/runtime/go-semacquire.c
+++ b/libgo/runtime/go-semacquire.c
@@ -44,7 +44,7 @@ acquire (uint32 *addr)
and it remains nonnegative. */
void
-semacquire (uint32 *addr)
+runtime_semacquire (uint32 *addr)
{
while (1)
{
@@ -86,7 +86,7 @@ semacquire (uint32 *addr)
process. */
void
-semrelease (uint32 *addr)
+runtime_semrelease (uint32 *addr)
{
int32_t val;
diff --git a/libgo/runtime/goc2c.c b/libgo/runtime/goc2c.c
index bf7483309bf..32fbceba1f5 100644
--- a/libgo/runtime/goc2c.c
+++ b/libgo/runtime/goc2c.c
@@ -2,22 +2,27 @@
// 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. */
+/*
+ * 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
- \}
+ 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. */
+/*
+ * 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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -87,20 +92,34 @@ static struct {
/* Fixed structure alignment (non-gcc only) */
int structround = 4;
+char *argv0;
+
+static void
+sysfatal(char *fmt, ...)
+{
+ char buf[256];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vsnprintf(buf, sizeof buf, fmt, arg);
+ va_end(arg);
+
+ fprintf(stderr, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
+ exit(1);
+}
+
/* Unexpected EOF. */
static void
bad_eof(void)
{
- fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno);
- exit(1);
+ sysfatal("%s:%ud: unexpected EOF\n", file, lineno);
}
/* Out of memory. */
static void
bad_mem(void)
{
- fprintf(stderr, "%s:%u: out of memory\n", file, lineno);
- exit(1);
+ sysfatal("%s:%ud: out of memory\n", file, lineno);
}
/* Allocate memory without fail. */
@@ -199,8 +218,10 @@ getchar_skipping_comments(void)
}
}
-/* Read and return a token. Tokens are delimited by whitespace or by
- [(),{}]. The latter are all returned as single characters. */
+/*
+ * 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)
{
@@ -262,11 +283,11 @@ read_package(void)
char *token;
token = read_token_no_eof();
+ if (token == NULL)
+ sysfatal("%s:%ud: no token\n", file, lineno);
if (strcmp(token, "package") != 0) {
- fprintf(stderr,
- "%s:%u: expected \"package\", got \"%s\"\n",
+ sysfatal("%s:%ud: expected \"package\", got \"%s\"\n",
file, lineno, token);
- exit(1);
}
return read_token_no_eof();
}
@@ -293,8 +314,10 @@ read_preprocessor_lines(void)
}
}
-/* Read a type in Go syntax and return a type in C syntax. We only
- permit basic types and pointers. */
+/*
+ * 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)
{
@@ -337,14 +360,15 @@ type_size(char *p)
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);
+ sysfatal("%s:%ud: unknown type %s\n", file, lineno, p);
}
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 '('. */
+/*
+ * 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)
{
@@ -380,17 +404,18 @@ read_params(int *poffset)
}
}
if (strcmp(token, ")") != 0) {
- fprintf(stderr, "%s:%u: expected '('\n",
+ sysfatal("%s:%ud: 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. */
+/*
+ * 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)
{
@@ -421,9 +446,8 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
token = read_token();
if (token == NULL || strcmp(token, "(") != 0) {
- fprintf(stderr, "%s:%u: expected \"(\"\n",
+ sysfatal("%s:%ud: expected \"(\"\n",
file, lineno);
- exit(1);
}
*params = read_params(paramwid);
@@ -435,9 +459,8 @@ read_func_header(char **name, struct params **params, int *paramwid, struct para
token = read_token();
}
if (token == NULL || strcmp(token, "{") != 0) {
- fprintf(stderr, "%s:%u: expected \"{\"\n",
+ sysfatal("%s:%ud: expected \"{\"\n",
file, lineno);
- exit(1);
}
return 1;
}
@@ -589,8 +612,10 @@ write_func_trailer(char *package, char *name,
write_6g_func_trailer(rets);
}
-/* Read and write the body of the function, ending in an unnested }
- (which is read but not written). */
+/*
+ * Read and write the body of the function, ending in an unnested }
+ * (which is read but not written).
+ */
static void
copy_body(void)
{
@@ -677,15 +702,15 @@ process_file(void)
static void
usage(void)
{
- fprintf(stderr, "Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
- exit(1);
+ sysfatal("Usage: goc2c [--6g | --gc] [--go-prefix PREFIX] [file]\n");
}
-int
+void
main(int argc, char **argv)
{
char *goarch;
+ argv0 = argv[0];
while(argc > 1 && argv[1][0] == '-') {
if(strcmp(argv[1], "-") == 0)
break;
@@ -706,7 +731,7 @@ main(int argc, char **argv)
if(argc <= 1 || strcmp(argv[1], "-") == 0) {
file = "<stdin>";
process_file();
- return 0;
+ exit(0);
}
if(argc > 2)
@@ -714,8 +739,7 @@ main(int argc, char **argv)
file = argv[1];
if(freopen(file, "r", stdin) == 0) {
- fprintf(stderr, "open %s: %s\n", file, strerror(errno));
- exit(1);
+ sysfatal("open %s: %r\n", file);
}
if(!gcc) {
@@ -731,5 +755,5 @@ main(int argc, char **argv)
}
process_file();
- return 0;
+ exit(0);
}
diff --git a/libgo/runtime/malloc.goc b/libgo/runtime/malloc.goc
index b46995ae0b6..2ea69ee795b 100644
--- a/libgo/runtime/malloc.goc
+++ b/libgo/runtime/malloc.goc
@@ -26,21 +26,6 @@ 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.
@@ -58,18 +43,18 @@ runtime_mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
if(size == 0)
size = 1;
- mstats.nmalloc++;
+ c = m->mcache;
+ c->local_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++;
+ c->local_alloc += size;
+ c->local_total_alloc += size;
+ c->local_by_size[sizeclass].nmalloc++;
} else {
// TODO(rsc): Report tracebacks for very large allocations.
@@ -81,8 +66,8 @@ runtime_mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
if(s == nil)
runtime_throw("out of memory");
size = npages<<PageShift;
- mstats.alloc += size;
- mstats.total_alloc += size;
+ c->local_alloc += size;
+ c->local_total_alloc += size;
v = (void*)(s->start << PageShift);
// setup for mark sweep
@@ -113,7 +98,7 @@ runtime_mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
// pick next profile time
if(rate > 0x3fffffff) // make 2*rate not overflow
rate = 0x3fffffff;
- m->mcache->next_sample = fastrand1() % (2*rate);
+ m->mcache->next_sample = runtime_fastrand1() % (2*rate);
profile:
runtime_setblockspecial(v);
runtime_MProf_Malloc(v, size);
@@ -158,6 +143,7 @@ __go_free(void *v)
// Find size class for v.
sizeclass = s->sizeclass;
+ c = m->mcache;
if(sizeclass == 0) {
// Large object.
size = s->npages<<PageShift;
@@ -169,18 +155,17 @@ __go_free(void *v)
runtime_MHeap_Free(&runtime_mheap, s, 1);
} else {
// Small object.
- c = m->mcache;
size = runtime_class_to_size[sizeclass];
- if(size > (int32)sizeof(uintptr))
+ if(size > sizeof(uintptr))
((uintptr*)v)[1] = 1; // mark as "needs to be zeroed"
// Must mark v freed before calling MCache_Free:
// it might coalesce v and other blocks into a bigger span
// and change the bitmap further.
runtime_markfreed(v, size);
- mstats.by_size[sizeclass].nfree++;
+ c->local_by_size[sizeclass].nfree++;
runtime_MCache_Free(c, v, sizeclass, size);
}
- mstats.alloc -= size;
+ c->local_alloc -= size;
if(prof)
runtime_MProf_Free(v, size);
@@ -197,7 +182,7 @@ runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
byte *p;
MSpan *s;
- mstats.nlookup++;
+ m->mcache->local_nlookup++;
s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
if(sp)
*sp = s;
@@ -226,9 +211,10 @@ runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
}
n = runtime_class_to_size[s->sizeclass];
- i = ((byte*)v - p)/n;
- if(base)
+ if(base) {
+ i = ((byte*)v - p)/n;
*base = p + i*n;
+ }
if(size)
*size = n;
@@ -260,7 +246,30 @@ runtime_allocmcache(void)
return c;
}
-extern int32 runtime_sizeof_C_MStats
+void
+runtime_purgecachedstats(M* m)
+{
+ MCache *c;
+
+ // Protected by either heap or GC lock.
+ c = m->mcache;
+ mstats.heap_alloc += c->local_cachealloc;
+ c->local_cachealloc = 0;
+ mstats.heap_objects += c->local_objects;
+ c->local_objects = 0;
+ mstats.nmalloc += c->local_nmalloc;
+ c->local_nmalloc = 0;
+ mstats.nfree += c->local_nfree;
+ c->local_nfree = 0;
+ mstats.nlookup += c->local_nlookup;
+ c->local_nlookup = 0;
+ mstats.alloc += c->local_alloc;
+ c->local_alloc= 0;
+ mstats.total_alloc += c->local_total_alloc;
+ c->local_total_alloc= 0;
+}
+
+extern uintptr runtime_sizeof_C_MStats
__asm__ ("libgo_runtime.runtime.Sizeof_C_MStats");
#define MaxArena32 (2U<<30)
diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h
index 8131e964e49..3e813bbde8c 100644
--- a/libgo/runtime/malloc.h
+++ b/libgo/runtime/malloc.h
@@ -80,7 +80,6 @@
// 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 MSpan MSpan;
@@ -186,10 +185,10 @@ void runtime_FixAlloc_Free(FixAlloc *f, void *p);
// Shared with Go: if you edit this structure, also edit extern.go.
struct MStats
{
- // General statistics. No locking; approximate.
+ // General statistics.
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 sys; // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
uint64 nlookup; // number of pointer lookups
uint64 nmalloc; // number of mallocs
uint64 nfree; // number of frees
@@ -222,7 +221,6 @@ struct MStats
bool debuggc;
// Statistics about allocation size classes.
- // No locking; approximate.
struct {
uint32 size;
uint64 nmalloc;
@@ -268,9 +266,20 @@ struct MCache
{
MCacheList list[NumSizeClasses];
uint64 size;
+ int64 local_cachealloc; // bytes allocated (or freed) from cache since last lock of heap
+ int64 local_objects; // objects allocated (or freed) from cache since last lock of heap
int64 local_alloc; // bytes allocated (or freed) since last lock of heap
- int64 local_objects; // objects allocated (or freed) since last lock of heap
+ int64 local_total_alloc; // bytes allocated (even if freed) since last lock of heap
+ int64 local_nmalloc; // number of mallocs since last lock of heap
+ int64 local_nfree; // number of frees since last lock of heap
+ int64 local_nlookup; // number of pointer lookups since last lock of heap
int32 next_sample; // trigger heap sample after allocating this many bytes
+ // Statistics about allocation size classes since last lock of heap
+ struct {
+ int64 nmalloc;
+ int64 nfree;
+ } local_by_size[NumSizeClasses];
+
};
void* runtime_MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
@@ -379,6 +388,7 @@ void runtime_markspan(void *v, uintptr size, uintptr n, bool leftover);
void runtime_unmarkspan(void *v, uintptr size);
bool runtime_blockspecial(void*);
void runtime_setblockspecial(void*);
+void runtime_purgecachedstats(M*);
enum
{
diff --git a/libgo/runtime/mcache.c b/libgo/runtime/mcache.c
index 65d849c16ea..191b0d1c3f2 100644
--- a/libgo/runtime/mcache.c
+++ b/libgo/runtime/mcache.c
@@ -48,7 +48,7 @@ runtime_MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
v->next = nil;
}
}
- c->local_alloc += size;
+ c->local_cachealloc += size;
c->local_objects++;
return v;
}
@@ -90,7 +90,7 @@ runtime_MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
l->list = p;
l->nlist++;
c->size += size;
- c->local_alloc -= size;
+ c->local_cachealloc -= size;
c->local_objects--;
if(l->nlist >= MaxMCacheListLen) {
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 0f28f5f6bd8..900ebde687c 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -443,6 +443,7 @@ sweep(void)
// Mark freed; restore block boundary bit.
*bitp = (*bitp & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
+ c = m->mcache;
if(s->sizeclass == 0) {
// Free large span.
runtime_unmarkspan(p, 1<<PageShift);
@@ -450,14 +451,13 @@ sweep(void)
runtime_MHeap_Free(&runtime_mheap, s, 1);
} else {
// Free small object.
- c = m->mcache;
if(size > sizeof(uintptr))
((uintptr*)p)[1] = 1; // mark as "needs to be zeroed"
- mstats.by_size[s->sizeclass].nfree++;
+ c->local_by_size[s->sizeclass].nfree++;
runtime_MCache_Free(c, p, s->sizeclass, size);
}
- mstats.alloc -= size;
- mstats.nfree++;
+ c->local_alloc -= size;
+ c->local_nfree++;
}
}
}
@@ -537,6 +537,7 @@ runtime_gc(int32 force __attribute__ ((unused)))
sweep();
t2 = runtime_nanotime();
__go_stealcache();
+ __go_cachestats();
mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*gcpercent/100;
m->gcing = 0;
@@ -584,6 +585,25 @@ runtime_gc(int32 force __attribute__ ((unused)))
runtime_gc(1);
}
+void runtime_UpdateMemStats(void)
+ __asm__("libgo_runtime.runtime.UpdateMemStats");
+
+void
+runtime_UpdateMemStats(void)
+{
+ // Have to acquire gcsema to stop the world,
+ // because stoptheworld can only be used by
+ // one goroutine at a time, and there might be
+ // a pending garbage collection already calling it.
+ pthread_mutex_lock(&gcsema);
+ m->gcing = 1;
+ runtime_stoptheworld();
+ __go_cachestats();
+ m->gcing = 0;
+ pthread_mutex_unlock(&gcsema);
+ runtime_starttheworld();
+}
+
static void
runfinq(void* dummy)
{
@@ -617,7 +637,7 @@ runfinq(void* dummy)
}
}
-#define runtime_gomaxprocs 2
+#define runtime_singleproc 0
// mark the block at v of size n as allocated.
// If noptr is true, mark it as having no pointers.
@@ -641,11 +661,11 @@ runtime_markallocated(void *v, uintptr n, bool noptr)
bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift);
if(noptr)
bits |= bitNoPointers<<shift;
- if(runtime_gomaxprocs == 1) {
+ if(runtime_singleproc) {
*b = bits;
break;
} else {
- // gomaxprocs > 1: use atomic op
+ // more than one goroutine is potentially running: use atomic op
if(runtime_casp((void**)b, (void*)obits, (void*)bits))
break;
}
@@ -671,11 +691,11 @@ runtime_markfreed(void *v, uintptr n)
for(;;) {
obits = *b;
bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift);
- if(runtime_gomaxprocs == 1) {
+ if(runtime_singleproc) {
*b = bits;
break;
} else {
- // gomaxprocs > 1: use atomic op
+ // more than one goroutine is potentially running: use atomic op
if(runtime_casp((void**)b, (void*)obits, (void*)bits))
break;
}
@@ -782,11 +802,11 @@ runtime_setblockspecial(void *v)
for(;;) {
obits = *b;
bits = obits | (bitSpecial<<shift);
- if(runtime_gomaxprocs == 1) {
+ if(runtime_singleproc) {
*b = bits;
break;
} else {
- // gomaxprocs > 1: use atomic op
+ // more than one goroutine is potentially running: use atomic op
if(runtime_casp((void**)b, (void*)obits, (void*)bits))
break;
}
diff --git a/libgo/runtime/mheap.c b/libgo/runtime/mheap.c
index cc6b3aff423..cacac7d6037 100644
--- a/libgo/runtime/mheap.c
+++ b/libgo/runtime/mheap.c
@@ -58,10 +58,7 @@ 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;
+ runtime_purgecachedstats(m);
s = MHeap_AllocLocked(h, npage, sizeclass);
if(s != nil) {
mstats.heap_inuse += npage<<PageShift;
@@ -259,10 +256,7 @@ 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;
+ runtime_purgecachedstats(m);
mstats.heap_inuse -= s->npages<<PageShift;
if(acct) {
mstats.heap_alloc -= s->npages<<PageShift;
diff --git a/libgo/runtime/mprof.goc b/libgo/runtime/mprof.goc
index 2e147edda02..d87be429d85 100644
--- a/libgo/runtime/mprof.goc
+++ b/libgo/runtime/mprof.goc
@@ -115,7 +115,7 @@ static uintptr addrmem;
// 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.
+// of the multiplied value.
enum {
HashMultiplier = 2654435769U
};
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index bf07c1219ba..ddc99eb6fb7 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -50,6 +50,7 @@ typedef uint8 bool;
typedef uint8 byte;
typedef struct M M;
typedef struct MCache MCache;
+typedef struct FixAlloc FixAlloc;
typedef struct Lock Lock;
/* We use mutexes for locks. 6g uses futexes directly, and perhaps
@@ -95,6 +96,7 @@ enum
struct M
{
+ int32 id;
int32 mallocing;
int32 gcing;
int32 locks;
@@ -103,6 +105,7 @@ struct M
int32 holds_finlock;
int32 gcing_for_finlock;
int32 profilehz;
+ uint32 fastrand;
MCache *mcache;
/* For the list of all threads. */
@@ -152,8 +155,8 @@ 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");
+void runtime_semacquire (uint32 *) asm ("libgo_runtime.runtime.Semacquire");
+void runtime_semrelease (uint32 *) asm ("libgo_runtime.runtime.Semrelease");
/*
* sleep and wakeup on one-time events.
@@ -192,6 +195,7 @@ void runtime_sigprof(uint8 *pc, uint8 *sp, uint8 *lr);
void runtime_cpuprofinit(void);
void runtime_resetcpuprofiler(int32);
void runtime_setcpuprofilerate(void(*)(uintptr*, int32), int32);
+uint32 runtime_fastrand1(void);
struct __go_func_type;
void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool,
diff --git a/libgo/syscalls/exec.go b/libgo/syscalls/exec.go
index 450c7e5938d..04d0ef88f82 100644
--- a/libgo/syscalls/exec.go
+++ b/libgo/syscalls/exec.go
@@ -13,8 +13,14 @@ import "unsafe"
func libc_fcntl(fd int, cmd int, arg int) int __asm__ ("fcntl")
func libc_fork() Pid_t __asm__ ("fork")
func libc_setsid() Pid_t __asm__ ("setsid")
+func libc_setpgid(Pid_t, Pid_t) int __asm__ ("setpgid")
+func libc_chroot(path *byte) int __asm__ ("chroot")
+func libc_setuid(Uid_t) int __asm__ ("setuid")
+func libc_setgid(Gid_t) int __asm__ ("setgid")
+func libc_setgroups(Size_t, *Gid_t) int __asm__ ("setgroups")
func libc_chdir(name *byte) int __asm__ ("chdir")
func libc_dup2(int, int) int __asm__ ("dup2")
+func libc_ioctl(int, int) int __asm__ ("ioctl")
func libc_execve(*byte, **byte, **byte) int __asm__ ("execve")
func libc_sysexit(int) __asm__ ("_exit")
@@ -24,7 +30,7 @@ func libc_sysexit(int) __asm__ ("_exit")
// 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, envv []*byte, dir *byte, attr *ProcAttr, pipe int) (pid int, err int) {
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err int) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., err1).
var r1, r2, err1 uintptr
@@ -51,19 +57,51 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, dir *byte, attr *ProcAt
// Fork succeeded, now in child.
// Enable tracing if requested.
- if attr.Ptrace {
+ if sys.Ptrace {
if libc_ptrace(_PTRACE_TRACEME, 0, 0, nil) < 0 {
goto childerror
}
}
// Session ID
- if attr.Setsid {
+ if sys.Setsid {
if libc_setsid() == Pid_t(-1) {
goto childerror
}
}
+ // Set process group
+ if sys.Setpgid {
+ if libc_setpgid(0, 0) < 0 {
+ goto childerror
+ }
+ }
+
+ // Chroot
+ if chroot != nil {
+ if libc_chroot(chroot) < 0 {
+ goto childerror
+ }
+ }
+
+ // User and groups
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
+ var groups *Gid_t
+ if ngroups > 0 {
+ groups = (*Gid_t)(unsafe.Pointer(&cred.Groups[0]))
+ }
+ if libc_setgroups(Size_t(ngroups), groups) < 0 {
+ goto childerror
+ }
+ if libc_setgid(Gid_t(cred.Gid)) < 0 {
+ goto childerror
+ }
+ if libc_setuid(Uid_t(cred.Uid)) < 0 {
+ goto childerror
+ }
+ }
+
// Chdir
if dir != nil {
if libc_chdir(dir) < 0 {
@@ -129,6 +167,20 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, dir *byte, attr *ProcAt
libc_close(i)
}
+ // Detach fd 0 from tty
+ if sys.Noctty {
+ if libc_ioctl(0, TIOCNOTTY) < 0 {
+ goto childerror
+ }
+ }
+
+ // Make fd 0 the tty
+ if sys.Setctty {
+ if libc_ioctl(0, TIOCSCTTY) < 0 {
+ goto childerror
+ }
+ }
+
// Time to exec.
libc_execve(argv0, &argv[0], &envv[0])
@@ -147,16 +199,35 @@ childerror:
panic("unreached")
}
+// Credential holds user and group identities to be assumed
+// by a child process started by StartProcess.
+type Credential struct {
+ Uid uint32 // User ID.
+ Gid uint32 // Group ID.
+ Groups []uint32 // Supplementary group IDs.
+}
+// ProcAttr holds attributes that will be applied to a new process started
+// by StartProcess.
type ProcAttr struct {
- Setsid bool // Create session.
- Ptrace bool // Enable tracing.
- Dir string // Current working directory.
- Env []string // Environment.
- Files []int // File descriptors.
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []int // File descriptors.
+ Sys *SysProcAttr
}
-var zeroAttributes ProcAttr
+type SysProcAttr struct {
+ Chroot string // Chroot.
+ Credential *Credential // Credential.
+ Ptrace bool // Enable tracing.
+ Setsid bool // Create session.
+ Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
+ Setctty bool // Set controlling terminal to fd 0
+ Noctty bool // Detach fd 0 from controlling terminal
+}
+
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var p [2]int
@@ -165,7 +236,11 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var wstatus WaitStatus
if attr == nil {
- attr = &zeroAttributes
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
}
p[0] = -1
@@ -180,6 +255,10 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
argvp[0] = argv0p
}
+ var chroot *byte
+ if sys.Chroot != "" {
+ chroot = StringBytePtr(sys.Chroot)
+ }
var dir *byte
if attr.Dir != "" {
dir = StringBytePtr(attr.Dir)
@@ -202,7 +281,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
}
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvp, dir, attr, p[1])
+ pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
if err != 0 {
error:
if p[0] >= 0 {
diff --git a/libgo/syscalls/netlink_linux.go b/libgo/syscalls/netlink_linux.go
new file mode 100644
index 00000000000..6f621cee69c
--- /dev/null
+++ b/libgo/syscalls/netlink_linux.go
@@ -0,0 +1,227 @@
+// 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.
+
+// Netlink sockets and messages
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+// Round the length of a netlink message up to align it properly.
+func nlmAlignOf(msglen int) int {
+ return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1)
+}
+
+// Round the length of a netlink route attribute up to align it
+// properly.
+func rtaAlignOf(attrlen int) int {
+ return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1)
+}
+
+// NetlinkRouteRequest represents the request message to receive
+// routing and link states from the kernel.
+type NetlinkRouteRequest struct {
+ Header NlMsghdr
+ Data RtGenmsg
+}
+
+func (rr *NetlinkRouteRequest) toWireFormat() []byte {
+ b := make([]byte, rr.Header.Len)
+ b[0] = byte(rr.Header.Len)
+ b[1] = byte(rr.Header.Len >> 8)
+ b[2] = byte(rr.Header.Len >> 16)
+ b[3] = byte(rr.Header.Len >> 24)
+ b[4] = byte(rr.Header.Type)
+ b[5] = byte(rr.Header.Type >> 8)
+ b[6] = byte(rr.Header.Flags)
+ b[7] = byte(rr.Header.Flags >> 8)
+ b[8] = byte(rr.Header.Seq)
+ b[9] = byte(rr.Header.Seq >> 8)
+ b[10] = byte(rr.Header.Seq >> 16)
+ b[11] = byte(rr.Header.Seq >> 24)
+ b[12] = byte(rr.Header.Pid)
+ b[13] = byte(rr.Header.Pid >> 8)
+ b[14] = byte(rr.Header.Pid >> 16)
+ b[15] = byte(rr.Header.Pid >> 24)
+ b[16] = byte(rr.Data.Family)
+ return b
+}
+
+func newNetlinkRouteRequest(proto, seq, family int) []byte {
+ rr := &NetlinkRouteRequest{}
+ rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg)
+ rr.Header.Type = uint16(proto)
+ rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST
+ rr.Header.Seq = uint32(seq)
+ rr.Data.Family = uint8(family)
+ return rr.toWireFormat()
+}
+
+// NetlinkRIB returns routing information base, as known as RIB,
+// which consists of network facility information, states and
+// parameters.
+func NetlinkRIB(proto, family int) ([]byte, int) {
+ var (
+ s int
+ e int
+ lsanl SockaddrNetlink
+ seq int
+ tab []byte
+ )
+
+ s, e = Socket(AF_NETLINK, SOCK_RAW, 0)
+ if e != 0 {
+ return nil, e
+ }
+ defer Close(s)
+
+ lsanl.Family = AF_NETLINK
+ e = Bind(s, &lsanl)
+ if e != 0 {
+ return nil, e
+ }
+
+ seq++
+ wb := newNetlinkRouteRequest(proto, seq, family)
+ e = Sendto(s, wb, 0, &lsanl)
+ if e != 0 {
+ return nil, e
+ }
+
+ for {
+ var (
+ rb []byte
+ nr int
+ lsa Sockaddr
+ )
+
+ rb = make([]byte, Getpagesize())
+ nr, _, e = Recvfrom(s, rb, 0)
+ if e != 0 {
+ return nil, e
+ }
+ if nr < NLMSG_HDRLEN {
+ return nil, EINVAL
+ }
+ rb = rb[:nr]
+ tab = append(tab, rb...)
+
+ msgs, _ := ParseNetlinkMessage(rb)
+ for _, m := range msgs {
+ if lsa, e = Getsockname(s); e != 0 {
+ return nil, e
+ }
+ switch v := lsa.(type) {
+ case *SockaddrNetlink:
+ if m.Header.Seq != uint32(seq) || m.Header.Pid != v.Pid {
+ return nil, EINVAL
+ }
+ default:
+ return nil, EINVAL
+ }
+ if m.Header.Type == NLMSG_DONE {
+ goto done
+ }
+ if m.Header.Type == NLMSG_ERROR {
+ return nil, EINVAL
+ }
+ }
+ }
+
+done:
+ return tab, 0
+}
+
+// NetlinkMessage represents the netlink message.
+type NetlinkMessage struct {
+ Header NlMsghdr
+ Data []byte
+}
+
+// ParseNetlinkMessage parses buf as netlink messages and returns
+// the slice containing the NetlinkMessage structs.
+func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, int) {
+ var (
+ h *NlMsghdr
+ dbuf []byte
+ dlen int
+ e int
+ msgs []NetlinkMessage
+ )
+
+ for len(buf) >= NLMSG_HDRLEN {
+ h, dbuf, dlen, e = netlinkMessageHeaderAndData(buf)
+ if e != 0 {
+ break
+ }
+ m := NetlinkMessage{}
+ m.Header = *h
+ m.Data = dbuf[:int(h.Len)-NLMSG_HDRLEN]
+ msgs = append(msgs, m)
+ buf = buf[dlen:]
+ }
+
+ return msgs, e
+}
+
+func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, int) {
+ h := (*NlMsghdr)(unsafe.Pointer(&buf[0]))
+ if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(buf) {
+ return nil, nil, 0, EINVAL
+ }
+ return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), 0
+}
+
+// NetlinkRouteAttr represents the netlink route attribute.
+type NetlinkRouteAttr struct {
+ Attr RtAttr
+ Value []byte
+}
+
+// ParseNetlinkRouteAttr parses msg's payload as netlink route
+// attributes and returns the slice containing the NetlinkRouteAttr
+// structs.
+func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
+ var (
+ buf []byte
+ a *RtAttr
+ alen int
+ vbuf []byte
+ e int
+ attrs []NetlinkRouteAttr
+ )
+
+ switch msg.Header.Type {
+ case RTM_NEWLINK:
+ buf = msg.Data[SizeofIfInfomsg:]
+ case RTM_NEWADDR:
+ buf = msg.Data[SizeofIfAddrmsg:]
+ default:
+ return nil, EINVAL
+ }
+
+ for len(buf) >= SizeofRtAttr {
+ a, vbuf, alen, e = netlinkRouteAttrAndValue(buf)
+ if e != 0 {
+ break
+ }
+ ra := NetlinkRouteAttr{}
+ ra.Attr = *a
+ ra.Value = vbuf[:int(a.Len)-SizeofRtAttr]
+ attrs = append(attrs, ra)
+ buf = buf[alen:]
+ }
+
+ return attrs, 0
+}
+
+func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, int) {
+ h := (*RtAttr)(unsafe.Pointer(&buf[0]))
+ if int(h.Len) < SizeofRtAttr || int(h.Len) > len(buf) {
+ return nil, nil, 0, EINVAL
+ }
+ return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), 0
+}
diff --git a/libgo/syscalls/socket.go b/libgo/syscalls/socket.go
index 28581a523e0..be7a89b7ff2 100644
--- a/libgo/syscalls/socket.go
+++ b/libgo/syscalls/socket.go
@@ -131,7 +131,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
}
return sa, 0;
}
- return nil, EAFNOSUPPORT;
+ return anyToSockaddrOS(rsa)
}
func libc_accept(fd int, sa *RawSockaddrAny, len *Socklen_t) int __asm__ ("accept");
@@ -239,7 +239,7 @@ 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 SetsockoptIpMreq(fd, level, opt int, mreq *IpMreq) (errno int) {
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (errno int) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
}
diff --git a/libgo/syscalls/socket_bsd.go b/libgo/syscalls/socket_bsd.go
index f4d06b4f5b0..735baf98684 100644
--- a/libgo/syscalls/socket_bsd.go
+++ b/libgo/syscalls/socket_bsd.go
@@ -72,3 +72,7 @@ type RawSockaddr struct {
func BindToDevice(fd int, device string) (errno int) {
return ENOSYS
}
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+ return nil, EAFNOSUPPORT;
+}
diff --git a/libgo/syscalls/socket_irix.go b/libgo/syscalls/socket_irix.go
index e17f1642897..6f2aaaff4d0 100644
--- a/libgo/syscalls/socket_irix.go
+++ b/libgo/syscalls/socket_irix.go
@@ -78,7 +78,7 @@ func BindToDevice(fd int, device string) (errno int) {
// This could be enabled with -D_SGI_SOURCE, but conflicts with
// -D_XOPEN_SOURCE=500 required for msg_control etc. in struct msghgr, so
// simply provide it here.
-type IpMreq struct {
+type IPMreq struct {
Multiaddr [4]byte
Interface [4]byte
}
@@ -123,3 +123,7 @@ const (
EAI_OVERFLOW = 13
EAI_MAX = 14
)
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+ return nil, EAFNOSUPPORT;
+}
diff --git a/libgo/syscalls/socket_linux.go b/libgo/syscalls/socket_linux.go
index cdcdf4ff28b..57ea7c3ff1b 100644
--- a/libgo/syscalls/socket_linux.go
+++ b/libgo/syscalls/socket_linux.go
@@ -6,9 +6,55 @@
package syscall
+import "unsafe"
+
const SizeofSockaddrInet4 = 16
const SizeofSockaddrInet6 = 28
const SizeofSockaddrUnix = 110
+const SizeofSockaddrLinklayer = 20
+const SizeofSockaddrNetlink = 12
+
+type SockaddrLinklayer struct {
+ Protocol uint16
+ Ifindex int
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]byte
+ raw RawSockaddrLinklayer
+}
+
+func (sa *SockaddrLinklayer) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+ if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_PACKET
+ sa.raw.Protocol = sa.Protocol
+ sa.raw.Ifindex = int32(sa.Ifindex)
+ sa.raw.Hatype = sa.Hatype
+ sa.raw.Pkttype = sa.Pkttype
+ sa.raw.Halen = sa.Halen
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, 0
+}
+
+type SockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+ raw RawSockaddrNetlink
+}
+
+func (sa *SockaddrNetlink) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+ sa.raw.Family = AF_NETLINK
+ sa.raw.Pad = sa.Pad
+ sa.raw.Pid = sa.Pid
+ sa.raw.Groups = sa.Groups
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, 0
+}
type RawSockaddrInet4 struct {
Family uint16;
@@ -64,6 +110,23 @@ func (sa *RawSockaddrUnix) getLen() (int, int) {
return n, 0
}
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
type RawSockaddr struct {
Family uint16;
Data [14]int8;
@@ -73,3 +136,30 @@ type RawSockaddr struct {
func BindToDevice(fd int, device string) (errno int) {
return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device)
}
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+ switch rsa.Addr.Family {
+ case AF_NETLINK:
+ pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa))
+ sa := new(SockaddrNetlink)
+ sa.Family = pp.Family
+ sa.Pad = pp.Pad
+ sa.Pid = pp.Pid
+ sa.Groups = pp.Groups
+ return sa, 0
+
+ case AF_PACKET:
+ pp := (*RawSockaddrLinklayer)(unsafe.Pointer(rsa))
+ sa := new(SockaddrLinklayer)
+ sa.Protocol = pp.Protocol
+ sa.Ifindex = int(pp.Ifindex)
+ sa.Hatype = pp.Hatype
+ sa.Pkttype = pp.Pkttype
+ sa.Halen = pp.Halen
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+ }
+ return nil, EAFNOSUPPORT;
+}
diff --git a/libgo/syscalls/socket_solaris.go b/libgo/syscalls/socket_solaris.go
index 13fe727c33e..376707858a6 100644
--- a/libgo/syscalls/socket_solaris.go
+++ b/libgo/syscalls/socket_solaris.go
@@ -74,3 +74,7 @@ type RawSockaddr struct {
func BindToDevice(fd int, device string) (errno int) {
return ENOSYS
}
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+ return nil, EAFNOSUPPORT;
+}
diff --git a/libgo/syscalls/syscall_linux.go b/libgo/syscalls/syscall_linux.go
index bdb92c5f4ca..29c8b62403e 100644
--- a/libgo/syscalls/syscall_linux.go
+++ b/libgo/syscalls/syscall_linux.go
@@ -9,6 +9,7 @@ package syscall
import "unsafe"
func libc_ptrace(request int, pid Pid_t, addr uintptr, data *byte) _C_long __asm__ ("ptrace")
+func libc_sendfile(int, int, *Offset_t, Size_t) Ssize_t __asm__ ("sendfile")
var dummy *byte
const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
@@ -186,3 +187,20 @@ func Tgkill(tgid int, tid int, sig int) (errno int) {
uintptr(sig));
return int(err);
}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+ var o Offset_t
+ var po *Offset_t
+ if offset != nil {
+ o = Offset_t(*offset)
+ po = &o
+ }
+ w := libc_sendfile(outfd, infd, po, Size_t(count))
+ if offset != nil {
+ *offset = int64(o)
+ }
+ if w < 0 {
+ return 0, GetErrno()
+ }
+ return int(w), 0
+}
diff --git a/libgo/testsuite/Makefile.in b/libgo/testsuite/Makefile.in
index b990f490a5d..0acbbb3da4f 100644
--- a/libgo/testsuite/Makefile.in
+++ b/libgo/testsuite/Makefile.in
@@ -86,7 +86,6 @@ 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@
diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest
index 938f47551ca..83640782835 100755
--- a/libgo/testsuite/gotest
+++ b/libgo/testsuite/gotest
@@ -34,6 +34,7 @@ prefix=
dejagnu=no
timeout=60
testname=""
+trace=false
while $loop; do
case "x$1" in
x--srcdir)
@@ -103,6 +104,10 @@ while $loop; do
testname=`echo $1 | sed -e 's/^--testname=//'`
shift
;;
+ x--trace)
+ trace=true
+ shift
+ ;;
x-*)
loop=false
;;
@@ -288,10 +293,17 @@ if test -n "$prefix"; then
prefixarg="-fgo-prefix=$prefix"
fi
+if test "$trace" = "true"; then
+ echo $GC -g $prefixarg -c -I . -fno-toplevel-reorder -o _gotest_.o $gofiles $pkgbasefiles
+fi
$GC -g $prefixarg -c -I . -fno-toplevel-reorder -o _gotest_.o $gofiles $pkgbasefiles
+
if $havex; then
mkdir -p `dirname $package`
cp _gotest_.o `dirname $package`/lib`basename $package`.a
+ if test "$trace" = "true"; then
+ echo $GC -g -c -I . -fno-toplevel-reorder -o $xofile $xgofiles
+ fi
$GC -g -c -I . -fno-toplevel-reorder -o $xofile $xgofiles
fi
@@ -375,9 +387,19 @@ func main() {
case "x$dejagnu" in
xno)
+ if test "$trace" = "true"; then
+ echo ${GC} -g -c _testmain.go
+ fi
${GC} -g -c _testmain.go
+
+ if test "$trace" = "true"; then
+ echo ${GL} *.o ${GOLIBS}
+ fi
${GL} *.o ${GOLIBS}
+ if test "$trace" = "true"; then
+ echo ./a.out -test.short -test.timeout=$timeout "$@"
+ fi
./a.out -test.short -test.timeout=$timeout "$@" &
pid=$!
(sleep `expr $timeout + 10`